]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg/Xhci: Fill the 'interval' field for ISO endpoint context
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
... / ...
CommitLineData
1/** @file\r
2\r
3 XHCI transfer scheduling routines.\r
4\r
5Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Xhci.h"\r
17\r
18/**\r
19 Create a command transfer TRB to support XHCI command interfaces.\r
20\r
21 @param Xhc The XHCI Instance.\r
22 @param CmdTrb The cmd TRB to be executed.\r
23\r
24 @return Created URB or NULL.\r
25\r
26**/\r
27URB*\r
28XhcCreateCmdTrb (\r
29 IN USB_XHCI_INSTANCE *Xhc,\r
30 IN TRB_TEMPLATE *CmdTrb\r
31 )\r
32{\r
33 URB *Urb;\r
34\r
35 Urb = AllocateZeroPool (sizeof (URB));\r
36 if (Urb == NULL) {\r
37 return NULL;\r
38 }\r
39\r
40 Urb->Signature = XHC_URB_SIG;\r
41\r
42 Urb->Ring = &Xhc->CmdRing;\r
43 XhcSyncTrsRing (Xhc, Urb->Ring);\r
44 Urb->TrbNum = 1;\r
45 Urb->TrbStart = Urb->Ring->RingEnqueue;\r
46 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));\r
47 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
48 Urb->TrbEnd = Urb->TrbStart;\r
49\r
50 return Urb;\r
51}\r
52\r
53/**\r
54 Execute a XHCI cmd TRB pointed by CmdTrb.\r
55\r
56 @param Xhc The XHCI Instance.\r
57 @param CmdTrb The cmd TRB to be executed.\r
58 @param Timeout Indicates the maximum time, in millisecond, which the\r
59 transfer is allowed to complete.\r
60 @param EvtTrb The event TRB corresponding to the cmd TRB.\r
61\r
62 @retval EFI_SUCCESS The transfer was completed successfully.\r
63 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
64 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
65 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
66\r
67**/\r
68EFI_STATUS\r
69EFIAPI\r
70XhcCmdTransfer (\r
71 IN USB_XHCI_INSTANCE *Xhc,\r
72 IN TRB_TEMPLATE *CmdTrb,\r
73 IN UINTN Timeout,\r
74 OUT TRB_TEMPLATE **EvtTrb\r
75 )\r
76{\r
77 EFI_STATUS Status;\r
78 URB *Urb;\r
79\r
80 //\r
81 // Validate the parameters\r
82 //\r
83 if ((Xhc == NULL) || (CmdTrb == NULL)) {\r
84 return EFI_INVALID_PARAMETER;\r
85 }\r
86\r
87 Status = EFI_DEVICE_ERROR;\r
88\r
89 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
90 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: HC is halted\n"));\r
91 goto ON_EXIT;\r
92 }\r
93\r
94 //\r
95 // Create a new URB, then poll the execution status.\r
96 //\r
97 Urb = XhcCreateCmdTrb (Xhc, CmdTrb);\r
98\r
99 if (Urb == NULL) {\r
100 DEBUG ((EFI_D_ERROR, "XhcCmdTransfer: failed to create URB\n"));\r
101 Status = EFI_OUT_OF_RESOURCES;\r
102 goto ON_EXIT;\r
103 }\r
104\r
105 Status = XhcExecTransfer (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 XhcFreeUrb (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 Instance\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
137XhcCreateUrb (\r
138 IN USB_XHCI_INSTANCE *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 InitializeListHead (&Urb->UrbList);\r
162\r
163 Ep = &Urb->Ep;\r
164 Ep->BusAddr = BusAddr;\r
165 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);\r
166 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
167 Ep->DevSpeed = DevSpeed;\r
168 Ep->MaxPacket = MaxPacket;\r
169 Ep->Type = Type;\r
170\r
171 Urb->Request = Request;\r
172 Urb->Data = Data;\r
173 Urb->DataLen = DataLen;\r
174 Urb->Callback = Callback;\r
175 Urb->Context = Context;\r
176\r
177 Status = XhcCreateTransferTrb (Xhc, Urb);\r
178 ASSERT_EFI_ERROR (Status);\r
179 if (EFI_ERROR (Status)) {\r
180 DEBUG ((EFI_D_ERROR, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status));\r
181 FreePool (Urb);\r
182 Urb = NULL;\r
183 }\r
184\r
185 return Urb;\r
186}\r
187\r
188/**\r
189 Free an allocated URB.\r
190\r
191 @param Xhc The XHCI device.\r
192 @param Urb The URB to free.\r
193\r
194**/\r
195VOID\r
196XhcFreeUrb (\r
197 IN USB_XHCI_INSTANCE *Xhc,\r
198 IN URB *Urb\r
199 )\r
200{\r
201 if ((Xhc == NULL) || (Urb == NULL)) {\r
202 return;\r
203 }\r
204 \r
205 if (Urb->DataMap != NULL) {\r
206 Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);\r
207 }\r
208\r
209 FreePool (Urb);\r
210}\r
211\r
212/**\r
213 Create a transfer TRB.\r
214\r
215 @param Xhc The XHCI Instance\r
216 @param Urb The urb used to construct the transfer TRB.\r
217\r
218 @return Created TRB or NULL\r
219\r
220**/\r
221EFI_STATUS\r
222XhcCreateTransferTrb (\r
223 IN USB_XHCI_INSTANCE *Xhc,\r
224 IN URB *Urb\r
225 )\r
226{\r
227 VOID *OutputContext;\r
228 TRANSFER_RING *EPRing;\r
229 UINT8 EPType;\r
230 UINT8 SlotId;\r
231 UINT8 Dci;\r
232 TRB *TrbStart;\r
233 UINTN TotalLen;\r
234 UINTN Len;\r
235 UINTN TrbNum;\r
236 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
237 EFI_PHYSICAL_ADDRESS PhyAddr;\r
238 VOID *Map;\r
239 EFI_STATUS Status;\r
240\r
241 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
242 if (SlotId == 0) {\r
243 return EFI_DEVICE_ERROR;\r
244 }\r
245\r
246 Urb->Finished = FALSE;\r
247 Urb->StartDone = FALSE;\r
248 Urb->EndDone = FALSE;\r
249 Urb->Completed = 0;\r
250 Urb->Result = EFI_USB_NOERROR;\r
251\r
252 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
253 ASSERT (Dci < 32);\r
254 EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
255 Urb->Ring = EPRing;\r
256 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
257 if (Xhc->HcCParams.Data.Csz == 0) {\r
258 EPType = (UINT8) ((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;\r
259 } else {\r
260 EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
261 }\r
262 \r
263 if (Urb->Data != NULL) {\r
264 if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {\r
265 MapOp = EfiPciIoOperationBusMasterWrite;\r
266 } else {\r
267 MapOp = EfiPciIoOperationBusMasterRead;\r
268 }\r
269 \r
270 Len = Urb->DataLen;\r
271 Status = Xhc->PciIo->Map (Xhc->PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
272 \r
273 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
274 DEBUG ((EFI_D_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));\r
275 return EFI_OUT_OF_RESOURCES;\r
276 }\r
277 \r
278 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
279 Urb->DataMap = Map;\r
280 }\r
281\r
282 //\r
283 // Construct the TRB\r
284 //\r
285 XhcSyncTrsRing (Xhc, EPRing);\r
286 Urb->TrbStart = EPRing->RingEnqueue;\r
287 switch (EPType) {\r
288 case ED_CONTROL_BIDIR:\r
289 //\r
290 // For control transfer, create SETUP_STAGE_TRB first.\r
291 //\r
292 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
293 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
294 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;\r
295 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
296 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
297 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
298 TrbStart->TrbCtrSetup.Length = 8;\r
299 TrbStart->TrbCtrSetup.IntTarget = 0;\r
300 TrbStart->TrbCtrSetup.IOC = 1;\r
301 TrbStart->TrbCtrSetup.IDT = 1;\r
302 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;\r
303 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
304 TrbStart->TrbCtrSetup.TRT = 3;\r
305 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
306 TrbStart->TrbCtrSetup.TRT = 2;\r
307 } else {\r
308 TrbStart->TrbCtrSetup.TRT = 0;\r
309 }\r
310 //\r
311 // Update the cycle bit\r
312 //\r
313 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
314 Urb->TrbNum++;\r
315\r
316 //\r
317 // For control transfer, create DATA_STAGE_TRB.\r
318 //\r
319 if (Urb->DataLen > 0) {\r
320 XhcSyncTrsRing (Xhc, EPRing);\r
321 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
322 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->DataPhy);\r
323 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->DataPhy);\r
324 TrbStart->TrbCtrData.Length = (UINT32) Urb->DataLen;\r
325 TrbStart->TrbCtrData.TDSize = 0;\r
326 TrbStart->TrbCtrData.IntTarget = 0;\r
327 TrbStart->TrbCtrData.ISP = 1;\r
328 TrbStart->TrbCtrData.IOC = 1;\r
329 TrbStart->TrbCtrData.IDT = 0;\r
330 TrbStart->TrbCtrData.CH = 0;\r
331 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;\r
332 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
333 TrbStart->TrbCtrData.DIR = 1;\r
334 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
335 TrbStart->TrbCtrData.DIR = 0;\r
336 } else {\r
337 TrbStart->TrbCtrData.DIR = 0;\r
338 }\r
339 //\r
340 // Update the cycle bit\r
341 //\r
342 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
343 Urb->TrbNum++;\r
344 }\r
345 //\r
346 // For control transfer, create STATUS_STAGE_TRB.\r
347 // Get the pointer to next TRB for status stage use\r
348 //\r
349 XhcSyncTrsRing (Xhc, EPRing);\r
350 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
351 TrbStart->TrbCtrStatus.IntTarget = 0;\r
352 TrbStart->TrbCtrStatus.IOC = 1;\r
353 TrbStart->TrbCtrStatus.CH = 0;\r
354 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;\r
355 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
356 TrbStart->TrbCtrStatus.DIR = 0;\r
357 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
358 TrbStart->TrbCtrStatus.DIR = 1;\r
359 } else {\r
360 TrbStart->TrbCtrStatus.DIR = 0;\r
361 }\r
362 //\r
363 // Update the cycle bit\r
364 //\r
365 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
366 //\r
367 // Update the enqueue pointer\r
368 //\r
369 XhcSyncTrsRing (Xhc, EPRing);\r
370 Urb->TrbNum++;\r
371 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
372\r
373 break;\r
374\r
375 case ED_BULK_OUT:\r
376 case ED_BULK_IN:\r
377 TotalLen = 0;\r
378 Len = 0;\r
379 TrbNum = 0;\r
380 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
381 while (TotalLen < Urb->DataLen) {\r
382 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
383 Len = Urb->DataLen - TotalLen;\r
384 } else {\r
385 Len = 0x10000;\r
386 }\r
387 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
388 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
389 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
390 TrbStart->TrbNormal.Length = (UINT32) Len;\r
391 TrbStart->TrbNormal.TDSize = 0;\r
392 TrbStart->TrbNormal.IntTarget = 0;\r
393 TrbStart->TrbNormal.ISP = 1;\r
394 TrbStart->TrbNormal.IOC = 1;\r
395 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
396 //\r
397 // Update the cycle bit\r
398 //\r
399 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
400\r
401 XhcSyncTrsRing (Xhc, EPRing);\r
402 TrbNum++;\r
403 TotalLen += Len;\r
404 }\r
405\r
406 Urb->TrbNum = TrbNum;\r
407 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
408 break;\r
409\r
410 case ED_INTERRUPT_OUT:\r
411 case ED_INTERRUPT_IN:\r
412 TotalLen = 0;\r
413 Len = 0;\r
414 TrbNum = 0;\r
415 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
416 while (TotalLen < Urb->DataLen) {\r
417 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
418 Len = Urb->DataLen - TotalLen;\r
419 } else {\r
420 Len = 0x10000;\r
421 }\r
422 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
423 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
424 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
425 TrbStart->TrbNormal.Length = (UINT32) Len;\r
426 TrbStart->TrbNormal.TDSize = 0;\r
427 TrbStart->TrbNormal.IntTarget = 0;\r
428 TrbStart->TrbNormal.ISP = 1;\r
429 TrbStart->TrbNormal.IOC = 1;\r
430 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
431 //\r
432 // Update the cycle bit\r
433 //\r
434 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
435\r
436 XhcSyncTrsRing (Xhc, EPRing);\r
437 TrbNum++;\r
438 TotalLen += Len;\r
439 }\r
440\r
441 Urb->TrbNum = TrbNum;\r
442 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
443 break;\r
444\r
445 default:\r
446 DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));\r
447 ASSERT (FALSE);\r
448 break;\r
449 }\r
450\r
451 return EFI_SUCCESS;\r
452}\r
453\r
454\r
455/**\r
456 Initialize the XHCI host controller for schedule.\r
457\r
458 @param Xhc The XHCI Instance to be initialized.\r
459\r
460**/\r
461VOID\r
462XhcInitSched (\r
463 IN USB_XHCI_INSTANCE *Xhc\r
464 )\r
465{\r
466 VOID *Dcbaa;\r
467 EFI_PHYSICAL_ADDRESS DcbaaPhy;\r
468 UINT64 CmdRing;\r
469 EFI_PHYSICAL_ADDRESS CmdRingPhy; \r
470 UINTN Entries;\r
471 UINT32 MaxScratchpadBufs;\r
472 UINT64 *ScratchBuf;\r
473 EFI_PHYSICAL_ADDRESS ScratchPhy;\r
474 UINT64 *ScratchEntry;\r
475 EFI_PHYSICAL_ADDRESS ScratchEntryPhy;\r
476 UINT32 Index;\r
477 UINTN *ScratchEntryMap;\r
478 EFI_STATUS Status;\r
479\r
480 //\r
481 // Initialize memory management.\r
482 //\r
483 Xhc->MemPool = UsbHcInitMemPool (Xhc->PciIo);\r
484 ASSERT (Xhc->MemPool != NULL);\r
485\r
486 //\r
487 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
488 // to enable the device slots that system software is going to use.\r
489 //\r
490 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
491 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
492 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);\r
493\r
494 //\r
495 // The Device Context Base Address Array entry associated with each allocated Device Slot\r
496 // shall contain a 64-bit pointer to the base of the associated Device Context.\r
497 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
498 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
499 //\r
500 Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);\r
501 Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries);\r
502 ASSERT (Dcbaa != NULL);\r
503 ZeroMem (Dcbaa, Entries);\r
504\r
505 //\r
506 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
507 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
508 // mode (Run/Stop(R/S) ='1').\r
509 //\r
510 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
511 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
512 ASSERT (MaxScratchpadBufs <= 1023);\r
513 if (MaxScratchpadBufs != 0) {\r
514 //\r
515 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them\r
516 //\r
517 ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);\r
518 ASSERT (ScratchEntryMap != NULL);\r
519 Xhc->ScratchEntryMap = ScratchEntryMap;\r
520 \r
521 //\r
522 // Allocate the buffer to record the host address for each entry\r
523 //\r
524 ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);\r
525 ASSERT (ScratchEntry != NULL);\r
526 Xhc->ScratchEntry = ScratchEntry;\r
527\r
528 ScratchPhy = 0;\r
529 Status = UsbHcAllocateAlignedPages (\r
530 Xhc->PciIo,\r
531 EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
532 Xhc->PageSize,\r
533 (VOID **) &ScratchBuf, \r
534 &ScratchPhy,\r
535 &Xhc->ScratchMap\r
536 );\r
537 ASSERT_EFI_ERROR (Status);\r
538\r
539 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
540 Xhc->ScratchBuf = ScratchBuf;\r
541\r
542 //\r
543 // Allocate each scratch buffer\r
544 //\r
545 for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
546 ScratchEntryPhy = 0;\r
547 Status = UsbHcAllocateAlignedPages (\r
548 Xhc->PciIo,\r
549 EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
550 Xhc->PageSize,\r
551 (VOID **) &ScratchEntry[Index],\r
552 &ScratchEntryPhy,\r
553 (VOID **) &ScratchEntryMap[Index]\r
554 );\r
555 ASSERT_EFI_ERROR (Status);\r
556 ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);\r
557 //\r
558 // Fill with the PCI device address\r
559 //\r
560 *ScratchBuf++ = ScratchEntryPhy;\r
561 }\r
562 //\r
563 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
564 // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
565 //\r
566 *(UINT64 *)Dcbaa = (UINT64)(UINTN) ScratchPhy;\r
567 }\r
568\r
569 //\r
570 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
571 // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
572 //\r
573 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;\r
574 //\r
575 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
576 // So divide it to two 32-bytes width register access.\r
577 //\r
578 DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Entries);\r
579 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(DcbaaPhy));\r
580 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));\r
581\r
582 DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));\r
583\r
584 //\r
585 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
586 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
587 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
588 // always be '0'.\r
589 //\r
590 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
591 //\r
592 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
593 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
594 // So we set RCS as inverted PCS init value to let Command Ring empty\r
595 //\r
596 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;\r
597 CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, (VOID *)(UINTN) CmdRing, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
598 ASSERT ((CmdRingPhy & 0x3F) == 0);\r
599 CmdRingPhy |= XHC_CRCR_RCS;\r
600 //\r
601 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
602 // So divide it to two 32-bytes width register access.\r
603 //\r
604 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRingPhy));\r
605 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
606\r
607 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
608\r
609 //\r
610 // Disable the 'interrupter enable' bit in USB_CMD\r
611 // and clear IE & IP bit in all Interrupter X Management Registers.\r
612 //\r
613 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
614 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
615 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
616 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
617 }\r
618\r
619 //\r
620 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
621 //\r
622 CreateEventRing (Xhc, &Xhc->EventRing);\r
623 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));\r
624}\r
625\r
626/**\r
627 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
628 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
629 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
630 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
631 Stopped to the Running state.\r
632\r
633 @param Xhc The XHCI Instance.\r
634 @param Urb The urb which makes the endpoint halted.\r
635\r
636 @retval EFI_SUCCESS The recovery is successful.\r
637 @retval Others Failed to recovery halted endpoint.\r
638\r
639**/\r
640EFI_STATUS\r
641EFIAPI\r
642XhcRecoverHaltedEndpoint (\r
643 IN USB_XHCI_INSTANCE *Xhc,\r
644 IN URB *Urb\r
645 )\r
646{\r
647 EFI_STATUS Status;\r
648 UINT8 Dci;\r
649 UINT8 SlotId;\r
650\r
651 Status = EFI_SUCCESS;\r
652 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
653 if (SlotId == 0) {\r
654 return EFI_DEVICE_ERROR;\r
655 }\r
656 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
657 ASSERT (Dci < 32);\r
658 \r
659 DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
660\r
661 //\r
662 // 1) Send Reset endpoint command to transit from halt to stop state\r
663 //\r
664 Status = XhcResetEndpoint(Xhc, SlotId, Dci);\r
665 if (EFI_ERROR(Status)) {\r
666 DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
667 goto Done;\r
668 }\r
669\r
670 //\r
671 // 2)Set dequeue pointer\r
672 //\r
673 Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
674 if (EFI_ERROR(Status)) {\r
675 DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
676 goto Done;\r
677 }\r
678\r
679 //\r
680 // 3)Ring the doorbell to transit from stop to active\r
681 //\r
682 XhcRingDoorBell (Xhc, SlotId, Dci);\r
683\r
684Done:\r
685 return Status;\r
686}\r
687\r
688/**\r
689 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
690 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
691 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
692 state.\r
693\r
694 @param Xhc The XHCI Instance.\r
695 @param Urb The urb which doesn't get completed in a specified timeout range.\r
696\r
697 @retval EFI_SUCCESS The dequeuing of the TDs is successful.\r
698 @retval Others Failed to stop the endpoint and dequeue the TDs.\r
699\r
700**/\r
701EFI_STATUS\r
702EFIAPI\r
703XhcDequeueTrbFromEndpoint (\r
704 IN USB_XHCI_INSTANCE *Xhc,\r
705 IN URB *Urb\r
706 )\r
707{\r
708 EFI_STATUS Status;\r
709 UINT8 Dci;\r
710 UINT8 SlotId;\r
711\r
712 Status = EFI_SUCCESS;\r
713 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
714 if (SlotId == 0) {\r
715 return EFI_DEVICE_ERROR;\r
716 }\r
717 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
718 ASSERT (Dci < 32);\r
719 \r
720 DEBUG ((EFI_D_INFO, "Stop Slot = %x,Dci = %x\n", SlotId, Dci));\r
721\r
722 //\r
723 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint\r
724 //\r
725 Status = XhcStopEndpoint(Xhc, SlotId, Dci);\r
726 if (EFI_ERROR(Status)) {\r
727 DEBUG ((EFI_D_ERROR, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
728 goto Done;\r
729 }\r
730\r
731 //\r
732 // 2)Set dequeue pointer\r
733 //\r
734 Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
735 if (EFI_ERROR(Status)) {\r
736 DEBUG ((EFI_D_ERROR, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
737 goto Done;\r
738 }\r
739\r
740 //\r
741 // 3)Ring the doorbell to transit from stop to active\r
742 //\r
743 XhcRingDoorBell (Xhc, SlotId, Dci);\r
744\r
745Done:\r
746 return Status;\r
747}\r
748\r
749/**\r
750 Create XHCI event ring.\r
751\r
752 @param Xhc The XHCI Instance.\r
753 @param EventRing The created event ring.\r
754\r
755**/\r
756VOID\r
757CreateEventRing (\r
758 IN USB_XHCI_INSTANCE *Xhc,\r
759 OUT EVENT_RING *EventRing\r
760 )\r
761{\r
762 VOID *Buf;\r
763 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
764 UINTN Size;\r
765 EFI_PHYSICAL_ADDRESS ERSTPhy;\r
766 EFI_PHYSICAL_ADDRESS DequeuePhy;\r
767\r
768 ASSERT (EventRing != NULL);\r
769\r
770 Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;\r
771 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
772 ASSERT (Buf != NULL);\r
773 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
774 ZeroMem (Buf, Size);\r
775\r
776 EventRing->EventRingSeg0 = Buf;\r
777 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
778 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
779 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
780 \r
781 DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
782 \r
783 //\r
784 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
785 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
786 //\r
787 EventRing->EventRingCCS = 1;\r
788\r
789 Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;\r
790 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
791 ASSERT (Buf != NULL);\r
792 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
793 ZeroMem (Buf, Size);\r
794\r
795 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
796 EventRing->ERSTBase = ERSTBase;\r
797 ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);\r
798 ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);\r
799 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
800\r
801 ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, ERSTBase, Size);\r
802\r
803 //\r
804 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
805 //\r
806 XhcWriteRuntimeReg (\r
807 Xhc,\r
808 XHC_ERSTSZ_OFFSET,\r
809 ERST_NUMBER\r
810 );\r
811 //\r
812 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
813 //\r
814 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
815 // So divide it to two 32-bytes width register access.\r
816 //\r
817 XhcWriteRuntimeReg (\r
818 Xhc,\r
819 XHC_ERDP_OFFSET,\r
820 XHC_LOW_32BIT((UINT64)(UINTN)DequeuePhy)\r
821 );\r
822 XhcWriteRuntimeReg (\r
823 Xhc,\r
824 XHC_ERDP_OFFSET + 4,\r
825 XHC_HIGH_32BIT((UINT64)(UINTN)DequeuePhy)\r
826 );\r
827 //\r
828 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)\r
829 //\r
830 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
831 // So divide it to two 32-bytes width register access.\r
832 //\r
833 XhcWriteRuntimeReg (\r
834 Xhc,\r
835 XHC_ERSTBA_OFFSET,\r
836 XHC_LOW_32BIT((UINT64)(UINTN)ERSTPhy)\r
837 );\r
838 XhcWriteRuntimeReg (\r
839 Xhc,\r
840 XHC_ERSTBA_OFFSET + 4,\r
841 XHC_HIGH_32BIT((UINT64)(UINTN)ERSTPhy)\r
842 );\r
843 //\r
844 // Need set IMAN IE bit to enble the ring interrupt\r
845 //\r
846 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);\r
847}\r
848\r
849/**\r
850 Create XHCI transfer ring.\r
851\r
852 @param Xhc The XHCI Instance.\r
853 @param TrbNum The number of TRB in the ring.\r
854 @param TransferRing The created transfer ring.\r
855\r
856**/\r
857VOID\r
858CreateTransferRing (\r
859 IN USB_XHCI_INSTANCE *Xhc,\r
860 IN UINTN TrbNum,\r
861 OUT TRANSFER_RING *TransferRing\r
862 )\r
863{\r
864 VOID *Buf;\r
865 LINK_TRB *EndTrb;\r
866 EFI_PHYSICAL_ADDRESS PhyAddr;\r
867\r
868 Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);\r
869 ASSERT (Buf != NULL);\r
870 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
871 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
872\r
873 TransferRing->RingSeg0 = Buf;\r
874 TransferRing->TrbNumber = TrbNum;\r
875 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
876 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
877 TransferRing->RingPCS = 1;\r
878 //\r
879 // 4.9.2 Transfer Ring Management\r
880 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
881 // point to the first TRB in the ring.\r
882 //\r
883 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
884 EndTrb->Type = TRB_TYPE_LINK;\r
885 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
886 EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);\r
887 EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
888 //\r
889 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
890 //\r
891 EndTrb->TC = 1;\r
892 //\r
893 // Set Cycle bit as other TRB PCS init value\r
894 //\r
895 EndTrb->CycleBit = 0;\r
896}\r
897\r
898/**\r
899 Free XHCI event ring.\r
900\r
901 @param Xhc The XHCI Instance.\r
902 @param EventRing The event ring to be freed.\r
903\r
904**/\r
905EFI_STATUS\r
906EFIAPI\r
907XhcFreeEventRing (\r
908 IN USB_XHCI_INSTANCE *Xhc,\r
909 IN EVENT_RING *EventRing\r
910)\r
911{\r
912 if(EventRing->EventRingSeg0 == NULL) {\r
913 return EFI_SUCCESS;\r
914 }\r
915\r
916 //\r
917 // Free EventRing Segment 0\r
918 //\r
919 UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
920\r
921 //\r
922 // Free ESRT table\r
923 //\r
924 UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
925 return EFI_SUCCESS;\r
926}\r
927\r
928/**\r
929 Free the resouce allocated at initializing schedule.\r
930\r
931 @param Xhc The XHCI Instance.\r
932\r
933**/\r
934VOID\r
935XhcFreeSched (\r
936 IN USB_XHCI_INSTANCE *Xhc\r
937 )\r
938{\r
939 UINT32 Index;\r
940 UINT64 *ScratchEntry;\r
941 \r
942 if (Xhc->ScratchBuf != NULL) {\r
943 ScratchEntry = Xhc->ScratchEntry;\r
944 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
945 //\r
946 // Free Scratchpad Buffers\r
947 //\r
948 UsbHcFreeAlignedPages (Xhc->PciIo, (VOID*)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);\r
949 }\r
950 //\r
951 // Free Scratchpad Buffer Array\r
952 //\r
953 UsbHcFreeAlignedPages (Xhc->PciIo, Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);\r
954 FreePool (Xhc->ScratchEntryMap);\r
955 FreePool (Xhc->ScratchEntry);\r
956 }\r
957\r
958 if (Xhc->CmdRing.RingSeg0 != NULL) {\r
959 UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
960 Xhc->CmdRing.RingSeg0 = NULL;\r
961 }\r
962 \r
963 XhcFreeEventRing (Xhc,&Xhc->EventRing);\r
964\r
965 if (Xhc->DCBAA != NULL) {\r
966 UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof(UINT64));\r
967 Xhc->DCBAA = NULL;\r
968 }\r
969 \r
970 //\r
971 // Free memory pool at last\r
972 //\r
973 if (Xhc->MemPool != NULL) {\r
974 UsbHcFreeMemPool (Xhc->MemPool);\r
975 Xhc->MemPool = NULL;\r
976 }\r
977}\r
978\r
979/**\r
980 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.\r
981\r
982 @param Xhc The XHCI Instance.\r
983 @param Trb The TRB to be checked.\r
984 @param Urb The pointer to the matched Urb.\r
985\r
986 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.\r
987 @retval FALSE The Trb is not matched with any URBs in the async list.\r
988\r
989**/\r
990BOOLEAN\r
991IsAsyncIntTrb (\r
992 IN USB_XHCI_INSTANCE *Xhc,\r
993 IN TRB_TEMPLATE *Trb,\r
994 OUT URB **Urb\r
995 )\r
996{\r
997 LIST_ENTRY *Entry;\r
998 LIST_ENTRY *Next;\r
999 TRB_TEMPLATE *CheckedTrb;\r
1000 URB *CheckedUrb;\r
1001 UINTN Index;\r
1002\r
1003 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1004 CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1005 CheckedTrb = CheckedUrb->TrbStart;\r
1006 for (Index = 0; Index < CheckedUrb->TrbNum; Index++) {\r
1007 if (Trb == CheckedTrb) {\r
1008 *Urb = CheckedUrb;\r
1009 return TRUE;\r
1010 }\r
1011 CheckedTrb++;\r
1012 //\r
1013 // If the checked TRB is the link TRB at the end of the transfer ring,\r
1014 // recircle it to the head of the ring.\r
1015 //\r
1016 if (CheckedTrb->Type == TRB_TYPE_LINK) {\r
1017 CheckedTrb = (TRB_TEMPLATE*) CheckedUrb->Ring->RingSeg0;\r
1018 }\r
1019 }\r
1020 }\r
1021\r
1022 return FALSE;\r
1023}\r
1024\r
1025/**\r
1026 Check if the Trb is a transaction of the URB.\r
1027\r
1028 @param Trb The TRB to be checked\r
1029 @param Urb The transfer ring to be checked.\r
1030\r
1031 @retval TRUE It is a transaction of the URB.\r
1032 @retval FALSE It is not any transaction of the URB.\r
1033\r
1034**/\r
1035BOOLEAN\r
1036IsTransferRingTrb (\r
1037 IN TRB_TEMPLATE *Trb,\r
1038 IN URB *Urb\r
1039 )\r
1040{\r
1041 TRB_TEMPLATE *CheckedTrb;\r
1042 UINTN Index;\r
1043\r
1044 CheckedTrb = Urb->Ring->RingSeg0;\r
1045\r
1046 ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
1047\r
1048 for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {\r
1049 if (Trb == CheckedTrb) {\r
1050 return TRUE;\r
1051 }\r
1052 CheckedTrb++;\r
1053 }\r
1054\r
1055 return FALSE;\r
1056}\r
1057\r
1058/**\r
1059 Check the URB's execution result and update the URB's\r
1060 result accordingly.\r
1061\r
1062 @param Xhc The XHCI Instance.\r
1063 @param Urb The URB to check result.\r
1064\r
1065 @return Whether the result of URB transfer is finialized.\r
1066\r
1067**/\r
1068BOOLEAN\r
1069XhcCheckUrbResult (\r
1070 IN USB_XHCI_INSTANCE *Xhc,\r
1071 IN URB *Urb\r
1072 )\r
1073{\r
1074 EVT_TRB_TRANSFER *EvtTrb;\r
1075 TRB_TEMPLATE *TRBPtr;\r
1076 UINTN Index;\r
1077 UINT8 TRBType;\r
1078 EFI_STATUS Status;\r
1079 URB *AsyncUrb;\r
1080 URB *CheckedUrb;\r
1081 UINT64 XhcDequeue;\r
1082 UINT32 High;\r
1083 UINT32 Low;\r
1084 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1085\r
1086 ASSERT ((Xhc != NULL) && (Urb != NULL));\r
1087\r
1088 Status = EFI_SUCCESS;\r
1089 AsyncUrb = NULL;\r
1090\r
1091 if (Urb->Finished) {\r
1092 goto EXIT;\r
1093 }\r
1094\r
1095 EvtTrb = NULL;\r
1096\r
1097 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
1098 Urb->Result |= EFI_USB_ERR_SYSTEM;\r
1099 goto EXIT;\r
1100 }\r
1101\r
1102 //\r
1103 // Traverse the event ring to find out all new events from the previous check.\r
1104 //\r
1105 XhcSyncEventRing (Xhc, &Xhc->EventRing);\r
1106 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {\r
1107 Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));\r
1108 if (Status == EFI_NOT_READY) {\r
1109 //\r
1110 // All new events are handled, return directly.\r
1111 //\r
1112 goto EXIT;\r
1113 }\r
1114\r
1115 //\r
1116 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.\r
1117 //\r
1118 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
1119 continue;\r
1120 }\r
1121 \r
1122 //\r
1123 // Need convert pci device address to host address\r
1124 //\r
1125 PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));\r
1126 TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
1127\r
1128 //\r
1129 // Update the status of Urb according to the finished event regardless of whether\r
1130 // the urb is current checked one or in the XHCI's async transfer list.\r
1131 // This way is used to avoid that those completed async transfer events don't get\r
1132 // handled in time and are flushed by newer coming events.\r
1133 //\r
1134 if (IsTransferRingTrb (TRBPtr, Urb)) {\r
1135 CheckedUrb = Urb;\r
1136 } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) { \r
1137 CheckedUrb = AsyncUrb;\r
1138 } else {\r
1139 continue;\r
1140 }\r
1141 \r
1142 switch (EvtTrb->Completecode) {\r
1143 case TRB_COMPLETION_STALL_ERROR:\r
1144 CheckedUrb->Result |= EFI_USB_ERR_STALL;\r
1145 CheckedUrb->Finished = TRUE;\r
1146 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
1147 goto EXIT;\r
1148\r
1149 case TRB_COMPLETION_BABBLE_ERROR:\r
1150 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;\r
1151 CheckedUrb->Finished = TRUE;\r
1152 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
1153 goto EXIT;\r
1154\r
1155 case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
1156 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;\r
1157 CheckedUrb->Finished = TRUE;\r
1158 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));\r
1159 goto EXIT;\r
1160\r
1161 case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
1162 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1163 CheckedUrb->Finished = TRUE;\r
1164 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
1165 goto EXIT;\r
1166\r
1167 case TRB_COMPLETION_SHORT_PACKET:\r
1168 case TRB_COMPLETION_SUCCESS:\r
1169 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
1170 DEBUG ((EFI_D_VERBOSE, "XhcCheckUrbResult: short packet happens!\n"));\r
1171 }\r
1172\r
1173 TRBType = (UINT8) (TRBPtr->Type);\r
1174 if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
1175 (TRBType == TRB_TYPE_NORMAL) ||\r
1176 (TRBType == TRB_TYPE_ISOCH)) {\r
1177 CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);\r
1178 }\r
1179\r
1180 break;\r
1181\r
1182 default:\r
1183 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));\r
1184 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1185 CheckedUrb->Finished = TRUE;\r
1186 goto EXIT;\r
1187 }\r
1188\r
1189 //\r
1190 // Only check first and end Trb event address\r
1191 //\r
1192 if (TRBPtr == CheckedUrb->TrbStart) {\r
1193 CheckedUrb->StartDone = TRUE;\r
1194 }\r
1195\r
1196 if (TRBPtr == CheckedUrb->TrbEnd) {\r
1197 CheckedUrb->EndDone = TRUE;\r
1198 }\r
1199\r
1200 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {\r
1201 CheckedUrb->Finished = TRUE;\r
1202 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;\r
1203 }\r
1204 }\r
1205\r
1206EXIT:\r
1207\r
1208 //\r
1209 // Advance event ring to last available entry\r
1210 //\r
1211 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1212 // So divide it to two 32-bytes width register access.\r
1213 //\r
1214 Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);\r
1215 High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);\r
1216 XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);\r
1217\r
1218 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));\r
1219\r
1220 if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {\r
1221 //\r
1222 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1223 // So divide it to two 32-bytes width register access.\r
1224 //\r
1225 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);\r
1226 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
1227 }\r
1228\r
1229 return Urb->Finished;\r
1230}\r
1231\r
1232\r
1233/**\r
1234 Execute the transfer by polling the URB. This is a synchronous operation.\r
1235\r
1236 @param Xhc The XHCI Instance.\r
1237 @param CmdTransfer The executed URB is for cmd transfer or not.\r
1238 @param Urb The URB to execute.\r
1239 @param Timeout The time to wait before abort, in millisecond.\r
1240\r
1241 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
1242 @return EFI_TIMEOUT The transfer failed due to time out.\r
1243 @return EFI_SUCCESS The transfer finished OK.\r
1244\r
1245**/\r
1246EFI_STATUS\r
1247XhcExecTransfer (\r
1248 IN USB_XHCI_INSTANCE *Xhc,\r
1249 IN BOOLEAN CmdTransfer,\r
1250 IN URB *Urb,\r
1251 IN UINTN Timeout\r
1252 )\r
1253{\r
1254 EFI_STATUS Status;\r
1255 UINTN Index;\r
1256 UINT64 Loop;\r
1257 UINT8 SlotId;\r
1258 UINT8 Dci;\r
1259 BOOLEAN Finished;\r
1260\r
1261 if (CmdTransfer) {\r
1262 SlotId = 0;\r
1263 Dci = 0;\r
1264 } else {\r
1265 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1266 if (SlotId == 0) {\r
1267 return EFI_DEVICE_ERROR;\r
1268 }\r
1269 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
1270 ASSERT (Dci < 32);\r
1271 }\r
1272\r
1273 Status = EFI_SUCCESS;\r
1274 Loop = Timeout * XHC_1_MILLISECOND;\r
1275 if (Timeout == 0) {\r
1276 Loop = 0xFFFFFFFF;\r
1277 }\r
1278\r
1279 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1280\r
1281 for (Index = 0; Index < Loop; Index++) {\r
1282 Finished = XhcCheckUrbResult (Xhc, Urb);\r
1283 if (Finished) {\r
1284 break;\r
1285 }\r
1286 gBS->Stall (XHC_1_MICROSECOND);\r
1287 }\r
1288\r
1289 if (Index == Loop) {\r
1290 Urb->Result = EFI_USB_ERR_TIMEOUT;\r
1291 Status = EFI_TIMEOUT;\r
1292 } else if (Urb->Result != EFI_USB_NOERROR) {\r
1293 Status = EFI_DEVICE_ERROR;\r
1294 }\r
1295\r
1296 return Status;\r
1297}\r
1298\r
1299/**\r
1300 Delete a single asynchronous interrupt transfer for\r
1301 the device and endpoint.\r
1302\r
1303 @param Xhc The XHCI Instance.\r
1304 @param BusAddr The logical device address assigned by UsbBus driver.\r
1305 @param EpNum The endpoint of the target.\r
1306\r
1307 @retval EFI_SUCCESS An asynchronous transfer is removed.\r
1308 @retval EFI_NOT_FOUND No transfer for the device is found.\r
1309\r
1310**/\r
1311EFI_STATUS\r
1312XhciDelAsyncIntTransfer (\r
1313 IN USB_XHCI_INSTANCE *Xhc,\r
1314 IN UINT8 BusAddr,\r
1315 IN UINT8 EpNum\r
1316 )\r
1317{\r
1318 LIST_ENTRY *Entry;\r
1319 LIST_ENTRY *Next;\r
1320 URB *Urb;\r
1321 EFI_USB_DATA_DIRECTION Direction;\r
1322\r
1323 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
1324 EpNum &= 0x0F;\r
1325\r
1326 Urb = NULL;\r
1327\r
1328 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1329 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1330 if ((Urb->Ep.BusAddr == BusAddr) &&\r
1331 (Urb->Ep.EpAddr == EpNum) &&\r
1332 (Urb->Ep.Direction == Direction)) {\r
1333 RemoveEntryList (&Urb->UrbList);\r
1334 FreePool (Urb->Data);\r
1335 XhcFreeUrb (Xhc, Urb);\r
1336 return EFI_SUCCESS;\r
1337 }\r
1338 }\r
1339\r
1340 return EFI_NOT_FOUND;\r
1341}\r
1342\r
1343/**\r
1344 Remove all the asynchronous interrutp transfers.\r
1345\r
1346 @param Xhc The XHCI Instance.\r
1347\r
1348**/\r
1349VOID\r
1350XhciDelAllAsyncIntTransfers (\r
1351 IN USB_XHCI_INSTANCE *Xhc\r
1352 )\r
1353{\r
1354 LIST_ENTRY *Entry;\r
1355 LIST_ENTRY *Next;\r
1356 URB *Urb;\r
1357\r
1358 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1359 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1360 RemoveEntryList (&Urb->UrbList);\r
1361 FreePool (Urb->Data);\r
1362 XhcFreeUrb (Xhc, Urb);\r
1363 }\r
1364}\r
1365\r
1366/**\r
1367 Update the queue head for next round of asynchronous transfer\r
1368\r
1369 @param Xhc The XHCI Instance.\r
1370 @param Urb The URB to update\r
1371\r
1372**/\r
1373VOID\r
1374XhcUpdateAsyncRequest (\r
1375 IN USB_XHCI_INSTANCE *Xhc,\r
1376 IN URB *Urb\r
1377 )\r
1378{\r
1379 EFI_STATUS Status;\r
1380\r
1381 if (Urb->Result == EFI_USB_NOERROR) {\r
1382 Status = XhcCreateTransferTrb (Xhc, Urb);\r
1383 if (EFI_ERROR (Status)) {\r
1384 return;\r
1385 }\r
1386 Status = RingIntTransferDoorBell (Xhc, Urb);\r
1387 if (EFI_ERROR (Status)) {\r
1388 return;\r
1389 }\r
1390 }\r
1391}\r
1392\r
1393/**\r
1394 Flush data from PCI controller specific address to mapped system\r
1395 memory address.\r
1396\r
1397 @param Xhc The XHCI device.\r
1398 @param Urb The URB to unmap.\r
1399\r
1400 @retval EFI_SUCCESS Success to flush data to mapped system memory.\r
1401 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.\r
1402\r
1403**/\r
1404EFI_STATUS\r
1405XhcFlushAsyncIntMap (\r
1406 IN USB_XHCI_INSTANCE *Xhc,\r
1407 IN URB *Urb\r
1408 )\r
1409{\r
1410 EFI_STATUS Status;\r
1411 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1412 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
1413 EFI_PCI_IO_PROTOCOL *PciIo;\r
1414 UINTN Len;\r
1415 VOID *Map;\r
1416\r
1417 PciIo = Xhc->PciIo;\r
1418 Len = Urb->DataLen;\r
1419\r
1420 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
1421 MapOp = EfiPciIoOperationBusMasterWrite;\r
1422 } else {\r
1423 MapOp = EfiPciIoOperationBusMasterRead;\r
1424 }\r
1425\r
1426 if (Urb->DataMap != NULL) {\r
1427 Status = PciIo->Unmap (PciIo, Urb->DataMap);\r
1428 if (EFI_ERROR (Status)) {\r
1429 goto ON_ERROR;\r
1430 }\r
1431 }\r
1432\r
1433 Urb->DataMap = NULL;\r
1434\r
1435 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
1436 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
1437 goto ON_ERROR;\r
1438 }\r
1439\r
1440 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
1441 Urb->DataMap = Map;\r
1442 return EFI_SUCCESS;\r
1443\r
1444ON_ERROR:\r
1445 return EFI_DEVICE_ERROR;\r
1446}\r
1447\r
1448/**\r
1449 Interrupt transfer periodic check handler.\r
1450\r
1451 @param Event Interrupt event.\r
1452 @param Context Pointer to USB_XHCI_INSTANCE.\r
1453\r
1454**/\r
1455VOID\r
1456EFIAPI\r
1457XhcMonitorAsyncRequests (\r
1458 IN EFI_EVENT Event,\r
1459 IN VOID *Context\r
1460 )\r
1461{\r
1462 USB_XHCI_INSTANCE *Xhc;\r
1463 LIST_ENTRY *Entry;\r
1464 LIST_ENTRY *Next;\r
1465 UINT8 *ProcBuf;\r
1466 URB *Urb;\r
1467 UINT8 SlotId;\r
1468 EFI_STATUS Status;\r
1469 EFI_TPL OldTpl;\r
1470\r
1471 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1472\r
1473 Xhc = (USB_XHCI_INSTANCE*) Context;\r
1474\r
1475 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1476 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1477\r
1478 //\r
1479 // Make sure that the device is available before every check.\r
1480 //\r
1481 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1482 if (SlotId == 0) {\r
1483 continue;\r
1484 }\r
1485\r
1486 //\r
1487 // Check the result of URB execution. If it is still\r
1488 // active, check the next one.\r
1489 //\r
1490 XhcCheckUrbResult (Xhc, Urb);\r
1491\r
1492 if (!Urb->Finished) {\r
1493 continue;\r
1494 }\r
1495\r
1496 //\r
1497 // Flush any PCI posted write transactions from a PCI host\r
1498 // bridge to system memory.\r
1499 //\r
1500 Status = XhcFlushAsyncIntMap (Xhc, Urb);\r
1501 if (EFI_ERROR (Status)) {\r
1502 DEBUG ((EFI_D_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));\r
1503 }\r
1504\r
1505 //\r
1506 // Allocate a buffer then copy the transferred data for user.\r
1507 // If failed to allocate the buffer, update the URB for next\r
1508 // round of transfer. Ignore the data of this round.\r
1509 //\r
1510 ProcBuf = NULL;\r
1511 if (Urb->Result == EFI_USB_NOERROR) {\r
1512 ASSERT (Urb->Completed <= Urb->DataLen);\r
1513\r
1514 ProcBuf = AllocateZeroPool (Urb->Completed);\r
1515\r
1516 if (ProcBuf == NULL) {\r
1517 XhcUpdateAsyncRequest (Xhc, Urb);\r
1518 continue;\r
1519 }\r
1520\r
1521 CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
1522 }\r
1523\r
1524 //\r
1525 // Leave error recovery to its related device driver. A\r
1526 // common case of the error recovery is to re-submit the\r
1527 // interrupt transfer which is linked to the head of the\r
1528 // list. This function scans from head to tail. So the\r
1529 // re-submitted interrupt transfer's callback function\r
1530 // will not be called again in this round. Don't touch this\r
1531 // URB after the callback, it may have been removed by the\r
1532 // callback.\r
1533 //\r
1534 if (Urb->Callback != NULL) {\r
1535 //\r
1536 // Restore the old TPL, USB bus maybe connect device in\r
1537 // his callback. Some drivers may has a lower TPL restriction.\r
1538 //\r
1539 gBS->RestoreTPL (OldTpl);\r
1540 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
1541 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1542 }\r
1543\r
1544 if (ProcBuf != NULL) {\r
1545 gBS->FreePool (ProcBuf);\r
1546 }\r
1547\r
1548 XhcUpdateAsyncRequest (Xhc, Urb);\r
1549 }\r
1550 gBS->RestoreTPL (OldTpl);\r
1551}\r
1552\r
1553/**\r
1554 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
1555\r
1556 @param Xhc The XHCI Instance.\r
1557 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
1558 @param Port The port to be polled.\r
1559 @param PortState The port state.\r
1560\r
1561 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
1562 @retval Others Should not appear.\r
1563\r
1564**/\r
1565EFI_STATUS\r
1566EFIAPI\r
1567XhcPollPortStatusChange (\r
1568 IN USB_XHCI_INSTANCE *Xhc,\r
1569 IN USB_DEV_ROUTE ParentRouteChart,\r
1570 IN UINT8 Port,\r
1571 IN EFI_USB_PORT_STATUS *PortState\r
1572 )\r
1573{\r
1574 EFI_STATUS Status;\r
1575 UINT8 Speed;\r
1576 UINT8 SlotId;\r
1577 USB_DEV_ROUTE RouteChart;\r
1578\r
1579 Status = EFI_SUCCESS;\r
1580\r
1581 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
1582 return EFI_SUCCESS;\r
1583 }\r
1584\r
1585 if (ParentRouteChart.Dword == 0) {\r
1586 RouteChart.Route.RouteString = 0;\r
1587 RouteChart.Route.RootPortNum = Port + 1;\r
1588 RouteChart.Route.TierNum = 1;\r
1589 } else {\r
1590 if(Port < 14) {\r
1591 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
1592 } else {\r
1593 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
1594 }\r
1595 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
1596 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
1597 }\r
1598\r
1599 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1600 if (SlotId != 0) {\r
1601 if (Xhc->HcCParams.Data.Csz == 0) {\r
1602 Status = XhcDisableSlotCmd (Xhc, SlotId);\r
1603 } else {\r
1604 Status = XhcDisableSlotCmd64 (Xhc, SlotId);\r
1605 }\r
1606 }\r
1607\r
1608 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1609 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
1610 //\r
1611 // Has a device attached, Identify device speed after port is enabled.\r
1612 //\r
1613 Speed = EFI_USB_SPEED_FULL;\r
1614 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
1615 Speed = EFI_USB_SPEED_LOW;\r
1616 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
1617 Speed = EFI_USB_SPEED_HIGH;\r
1618 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
1619 Speed = EFI_USB_SPEED_SUPER;\r
1620 }\r
1621 //\r
1622 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
1623 //\r
1624 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1625 if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
1626 if (Xhc->HcCParams.Data.Csz == 0) {\r
1627 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1628 } else {\r
1629 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1630 }\r
1631 }\r
1632 } \r
1633\r
1634 return Status;\r
1635}\r
1636\r
1637\r
1638/**\r
1639 Calculate the device context index by endpoint address and direction.\r
1640\r
1641 @param EpAddr The target endpoint number.\r
1642 @param Direction The direction of the target endpoint.\r
1643\r
1644 @return The device context index of endpoint.\r
1645\r
1646**/\r
1647UINT8\r
1648XhcEndpointToDci (\r
1649 IN UINT8 EpAddr,\r
1650 IN UINT8 Direction\r
1651 )\r
1652{\r
1653 UINT8 Index;\r
1654\r
1655 if (EpAddr == 0) {\r
1656 return 1;\r
1657 } else {\r
1658 Index = (UINT8) (2 * EpAddr);\r
1659 if (Direction == EfiUsbDataIn) {\r
1660 Index += 1;\r
1661 }\r
1662 return Index;\r
1663 }\r
1664}\r
1665\r
1666/**\r
1667 Find out the actual device address according to the requested device address from UsbBus.\r
1668\r
1669 @param Xhc The XHCI Instance.\r
1670 @param BusDevAddr The requested device address by UsbBus upper driver.\r
1671\r
1672 @return The actual device address assigned to the device.\r
1673\r
1674**/\r
1675UINT8\r
1676EFIAPI\r
1677XhcBusDevAddrToSlotId (\r
1678 IN USB_XHCI_INSTANCE *Xhc,\r
1679 IN UINT8 BusDevAddr\r
1680 )\r
1681{\r
1682 UINT8 Index;\r
1683\r
1684 for (Index = 0; Index < 255; Index++) {\r
1685 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1686 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1687 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
1688 break;\r
1689 }\r
1690 }\r
1691\r
1692 if (Index == 255) {\r
1693 return 0;\r
1694 }\r
1695\r
1696 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1697}\r
1698\r
1699/**\r
1700 Find out the slot id according to the device's route string.\r
1701\r
1702 @param Xhc The XHCI Instance.\r
1703 @param RouteString The route string described the device location.\r
1704\r
1705 @return The slot id used by the device.\r
1706\r
1707**/\r
1708UINT8\r
1709EFIAPI\r
1710XhcRouteStringToSlotId (\r
1711 IN USB_XHCI_INSTANCE *Xhc,\r
1712 IN USB_DEV_ROUTE RouteString\r
1713 )\r
1714{\r
1715 UINT8 Index;\r
1716\r
1717 for (Index = 0; Index < 255; Index++) {\r
1718 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1719 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1720 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
1721 break;\r
1722 }\r
1723 }\r
1724\r
1725 if (Index == 255) {\r
1726 return 0;\r
1727 }\r
1728\r
1729 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1730}\r
1731\r
1732/**\r
1733 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
1734\r
1735 @param Xhc The XHCI Instance.\r
1736 @param EvtRing The event ring to sync.\r
1737\r
1738 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
1739\r
1740**/\r
1741EFI_STATUS\r
1742EFIAPI\r
1743XhcSyncEventRing (\r
1744 IN USB_XHCI_INSTANCE *Xhc,\r
1745 IN EVENT_RING *EvtRing\r
1746 )\r
1747{\r
1748 UINTN Index;\r
1749 TRB_TEMPLATE *EvtTrb1;\r
1750\r
1751 ASSERT (EvtRing != NULL);\r
1752\r
1753 //\r
1754 // Calculate the EventRingEnqueue and EventRingCCS.\r
1755 // Note: only support single Segment\r
1756 //\r
1757 EvtTrb1 = EvtRing->EventRingDequeue;\r
1758\r
1759 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
1760 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {\r
1761 break;\r
1762 }\r
1763\r
1764 EvtTrb1++;\r
1765\r
1766 if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
1767 EvtTrb1 = EvtRing->EventRingSeg0;\r
1768 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
1769 }\r
1770 }\r
1771\r
1772 if (Index < EvtRing->TrbNumber) {\r
1773 EvtRing->EventRingEnqueue = EvtTrb1;\r
1774 } else {\r
1775 ASSERT (FALSE);\r
1776 }\r
1777\r
1778 return EFI_SUCCESS;\r
1779}\r
1780\r
1781/**\r
1782 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
1783\r
1784 @param Xhc The XHCI Instance.\r
1785 @param TrsRing The transfer ring to sync.\r
1786\r
1787 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
1788\r
1789**/\r
1790EFI_STATUS\r
1791EFIAPI\r
1792XhcSyncTrsRing (\r
1793 IN USB_XHCI_INSTANCE *Xhc,\r
1794 IN TRANSFER_RING *TrsRing\r
1795 )\r
1796{\r
1797 UINTN Index;\r
1798 TRB_TEMPLATE *TrsTrb;\r
1799\r
1800 ASSERT (TrsRing != NULL);\r
1801 //\r
1802 // Calculate the latest RingEnqueue and RingPCS\r
1803 //\r
1804 TrsTrb = TrsRing->RingEnqueue;\r
1805 ASSERT (TrsTrb != NULL);\r
1806\r
1807 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
1808 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
1809 break;\r
1810 }\r
1811 TrsTrb++;\r
1812 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
1813 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);\r
1814 //\r
1815 // set cycle bit in Link TRB as normal\r
1816 //\r
1817 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
1818 //\r
1819 // Toggle PCS maintained by software\r
1820 //\r
1821 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
1822 TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address\r
1823 }\r
1824 }\r
1825\r
1826 ASSERT (Index != TrsRing->TrbNumber);\r
1827\r
1828 if (TrsTrb != TrsRing->RingEnqueue) {\r
1829 TrsRing->RingEnqueue = TrsTrb;\r
1830 }\r
1831\r
1832 //\r
1833 // Clear the Trb context for enqueue, but reserve the PCS bit\r
1834 //\r
1835 TrsTrb->Parameter1 = 0;\r
1836 TrsTrb->Parameter2 = 0;\r
1837 TrsTrb->Status = 0;\r
1838 TrsTrb->RsvdZ1 = 0;\r
1839 TrsTrb->Type = 0;\r
1840 TrsTrb->Control = 0;\r
1841\r
1842 return EFI_SUCCESS;\r
1843}\r
1844\r
1845/**\r
1846 Check if there is a new generated event.\r
1847\r
1848 @param Xhc The XHCI Instance.\r
1849 @param EvtRing The event ring to check.\r
1850 @param NewEvtTrb The new event TRB found.\r
1851\r
1852 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
1853 @retval EFI_NOT_READY The event ring has no new event.\r
1854\r
1855**/\r
1856EFI_STATUS\r
1857EFIAPI\r
1858XhcCheckNewEvent (\r
1859 IN USB_XHCI_INSTANCE *Xhc,\r
1860 IN EVENT_RING *EvtRing,\r
1861 OUT TRB_TEMPLATE **NewEvtTrb\r
1862 )\r
1863{\r
1864 ASSERT (EvtRing != NULL);\r
1865\r
1866 *NewEvtTrb = EvtRing->EventRingDequeue;\r
1867\r
1868 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
1869 return EFI_NOT_READY;\r
1870 }\r
1871\r
1872 EvtRing->EventRingDequeue++;\r
1873 //\r
1874 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
1875 //\r
1876 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
1877 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
1878 }\r
1879\r
1880 return EFI_SUCCESS;\r
1881}\r
1882\r
1883/**\r
1884 Ring the door bell to notify XHCI there is a transaction to be executed.\r
1885\r
1886 @param Xhc The XHCI Instance.\r
1887 @param SlotId The slot id of the target device.\r
1888 @param Dci The device context index of the target slot or endpoint.\r
1889\r
1890 @retval EFI_SUCCESS Successfully ring the door bell.\r
1891\r
1892**/\r
1893EFI_STATUS\r
1894EFIAPI\r
1895XhcRingDoorBell (\r
1896 IN USB_XHCI_INSTANCE *Xhc,\r
1897 IN UINT8 SlotId,\r
1898 IN UINT8 Dci\r
1899 )\r
1900{\r
1901 if (SlotId == 0) {\r
1902 XhcWriteDoorBellReg (Xhc, 0, 0);\r
1903 } else {\r
1904 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
1905 }\r
1906\r
1907 return EFI_SUCCESS;\r
1908}\r
1909\r
1910/**\r
1911 Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
1912\r
1913 @param Xhc The XHCI Instance.\r
1914 @param Urb The URB to be rung.\r
1915\r
1916 @retval EFI_SUCCESS Successfully ring the door bell.\r
1917\r
1918**/\r
1919EFI_STATUS\r
1920RingIntTransferDoorBell (\r
1921 IN USB_XHCI_INSTANCE *Xhc,\r
1922 IN URB *Urb\r
1923 )\r
1924{\r
1925 UINT8 SlotId;\r
1926 UINT8 Dci;\r
1927\r
1928 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1929 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
1930 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1931 return EFI_SUCCESS;\r
1932}\r
1933\r
1934/**\r
1935 Assign and initialize the device slot for a new device.\r
1936\r
1937 @param Xhc The XHCI Instance.\r
1938 @param ParentRouteChart The route string pointed to the parent device.\r
1939 @param ParentPort The port at which the device is located.\r
1940 @param RouteChart The route string pointed to the device.\r
1941 @param DeviceSpeed The device speed.\r
1942\r
1943 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
1944\r
1945**/\r
1946EFI_STATUS\r
1947EFIAPI\r
1948XhcInitializeDeviceSlot (\r
1949 IN USB_XHCI_INSTANCE *Xhc,\r
1950 IN USB_DEV_ROUTE ParentRouteChart,\r
1951 IN UINT16 ParentPort,\r
1952 IN USB_DEV_ROUTE RouteChart,\r
1953 IN UINT8 DeviceSpeed\r
1954 )\r
1955{\r
1956 EFI_STATUS Status;\r
1957 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1958 INPUT_CONTEXT *InputContext;\r
1959 DEVICE_CONTEXT *OutputContext;\r
1960 TRANSFER_RING *EndpointTransferRing;\r
1961 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
1962 UINT8 DeviceAddress;\r
1963 CMD_TRB_ENABLE_SLOT CmdTrb;\r
1964 UINT8 SlotId;\r
1965 UINT8 ParentSlotId;\r
1966 DEVICE_CONTEXT *ParentDeviceContext;\r
1967 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1968\r
1969 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
1970 CmdTrb.CycleBit = 1;\r
1971 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
1972\r
1973 Status = XhcCmdTransfer (\r
1974 Xhc,\r
1975 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
1976 XHC_GENERIC_TIMEOUT,\r
1977 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
1978 );\r
1979 if (EFI_ERROR (Status)) {\r
1980 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
1981 return Status;\r
1982 }\r
1983 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
1984 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
1985 SlotId = (UINT8)EvtTrb->SlotId;\r
1986 ASSERT (SlotId != 0);\r
1987\r
1988 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
1989 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
1990 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
1991 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
1992 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
1993\r
1994 //\r
1995 // 4.3.3 Device Slot Initialization\r
1996 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
1997 //\r
1998 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));\r
1999 ASSERT (InputContext != NULL);\r
2000 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
2001 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2002\r
2003 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
2004\r
2005 //\r
2006 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2007 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2008 // Context are affected by the command.\r
2009 //\r
2010 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
2011\r
2012 //\r
2013 // 3) Initialize the Input Slot Context data structure\r
2014 //\r
2015 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
2016 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2017 InputContext->Slot.ContextEntries = 1;\r
2018 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
2019\r
2020 if (RouteChart.Route.RouteString) {\r
2021 //\r
2022 // The device is behind of hub device.\r
2023 //\r
2024 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
2025 ASSERT (ParentSlotId != 0);\r
2026 //\r
2027 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2028 //\r
2029 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
2030 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2031 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
2032 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2033 //\r
2034 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2035 // environment from Full/Low speed signaling environment for a device\r
2036 //\r
2037 InputContext->Slot.TTPortNum = ParentPort;\r
2038 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2039 }\r
2040 } else {\r
2041 //\r
2042 // Inherit the TT parameters from parent device.\r
2043 //\r
2044 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2045 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2046 //\r
2047 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2048 //\r
2049 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2050 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2051 }\r
2052 }\r
2053 }\r
2054\r
2055 //\r
2056 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
2057 //\r
2058 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2059 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2060 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
2061 //\r
2062 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2063 //\r
2064 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2065\r
2066 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2067 InputContext->EP[0].MaxPacketSize = 512;\r
2068 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2069 InputContext->EP[0].MaxPacketSize = 64;\r
2070 } else {\r
2071 InputContext->EP[0].MaxPacketSize = 8;\r
2072 }\r
2073 //\r
2074 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2075 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2076 //\r
2077 InputContext->EP[0].AverageTRBLength = 8;\r
2078 InputContext->EP[0].MaxBurstSize = 0;\r
2079 InputContext->EP[0].Interval = 0;\r
2080 InputContext->EP[0].MaxPStreams = 0;\r
2081 InputContext->EP[0].Mult = 0;\r
2082 InputContext->EP[0].CErr = 3;\r
2083\r
2084 //\r
2085 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2086 //\r
2087 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2088 Xhc->MemPool,\r
2089 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2090 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2091 );\r
2092 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2093 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2094\r
2095 //\r
2096 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2097 //\r
2098 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));\r
2099 ASSERT (OutputContext != NULL);\r
2100 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2101 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
2102\r
2103 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
2104 //\r
2105 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2106 // a pointer to the Output Device Context data structure (6.2.1).\r
2107 //\r
2108 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
2109 //\r
2110 // Fill DCBAA with PCI device address\r
2111 //\r
2112 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
2113\r
2114 //\r
2115 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2116 // Context data structure described above.\r
2117 //\r
2118 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2119 // to device.\r
2120 //\r
2121 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
2122 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
2123 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
2124 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2125 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2126 CmdTrbAddr.CycleBit = 1;\r
2127 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
2128 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2129 Status = XhcCmdTransfer (\r
2130 Xhc,\r
2131 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
2132 XHC_GENERIC_TIMEOUT,\r
2133 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2134 );\r
2135 if (!EFI_ERROR (Status)) {\r
2136 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;\r
2137 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2138 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2139 }\r
2140\r
2141 return Status;\r
2142}\r
2143\r
2144/**\r
2145 Assign and initialize the device slot for a new device.\r
2146\r
2147 @param Xhc The XHCI Instance.\r
2148 @param ParentRouteChart The route string pointed to the parent device.\r
2149 @param ParentPort The port at which the device is located.\r
2150 @param RouteChart The route string pointed to the device.\r
2151 @param DeviceSpeed The device speed.\r
2152\r
2153 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
2154\r
2155**/\r
2156EFI_STATUS\r
2157EFIAPI\r
2158XhcInitializeDeviceSlot64 (\r
2159 IN USB_XHCI_INSTANCE *Xhc,\r
2160 IN USB_DEV_ROUTE ParentRouteChart,\r
2161 IN UINT16 ParentPort,\r
2162 IN USB_DEV_ROUTE RouteChart,\r
2163 IN UINT8 DeviceSpeed\r
2164 )\r
2165{\r
2166 EFI_STATUS Status;\r
2167 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2168 INPUT_CONTEXT_64 *InputContext;\r
2169 DEVICE_CONTEXT_64 *OutputContext;\r
2170 TRANSFER_RING *EndpointTransferRing;\r
2171 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2172 UINT8 DeviceAddress;\r
2173 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2174 UINT8 SlotId;\r
2175 UINT8 ParentSlotId;\r
2176 DEVICE_CONTEXT_64 *ParentDeviceContext;\r
2177 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2178\r
2179 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
2180 CmdTrb.CycleBit = 1;\r
2181 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
2182\r
2183 Status = XhcCmdTransfer (\r
2184 Xhc,\r
2185 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
2186 XHC_GENERIC_TIMEOUT,\r
2187 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2188 );\r
2189 if (EFI_ERROR (Status)) {\r
2190 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
2191 return Status;\r
2192 }\r
2193 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
2194 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
2195 SlotId = (UINT8)EvtTrb->SlotId;\r
2196 ASSERT (SlotId != 0);\r
2197\r
2198 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2199 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2200 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2201 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2202 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
2203\r
2204 //\r
2205 // 4.3.3 Device Slot Initialization\r
2206 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
2207 //\r
2208 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));\r
2209 ASSERT (InputContext != NULL);\r
2210 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
2211 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2212\r
2213 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
2214\r
2215 //\r
2216 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2217 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2218 // Context are affected by the command.\r
2219 //\r
2220 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
2221\r
2222 //\r
2223 // 3) Initialize the Input Slot Context data structure\r
2224 //\r
2225 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
2226 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2227 InputContext->Slot.ContextEntries = 1;\r
2228 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
2229\r
2230 if (RouteChart.Route.RouteString) {\r
2231 //\r
2232 // The device is behind of hub device.\r
2233 //\r
2234 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
2235 ASSERT (ParentSlotId != 0);\r
2236 //\r
2237 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2238 //\r
2239 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
2240 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2241 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
2242 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2243 //\r
2244 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2245 // environment from Full/Low speed signaling environment for a device\r
2246 //\r
2247 InputContext->Slot.TTPortNum = ParentPort;\r
2248 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2249 }\r
2250 } else {\r
2251 //\r
2252 // Inherit the TT parameters from parent device.\r
2253 //\r
2254 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2255 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2256 //\r
2257 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2258 //\r
2259 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2260 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2261 }\r
2262 }\r
2263 }\r
2264\r
2265 //\r
2266 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
2267 //\r
2268 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2269 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2270 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
2271 //\r
2272 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2273 //\r
2274 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2275\r
2276 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2277 InputContext->EP[0].MaxPacketSize = 512;\r
2278 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2279 InputContext->EP[0].MaxPacketSize = 64;\r
2280 } else {\r
2281 InputContext->EP[0].MaxPacketSize = 8;\r
2282 }\r
2283 //\r
2284 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2285 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2286 //\r
2287 InputContext->EP[0].AverageTRBLength = 8;\r
2288 InputContext->EP[0].MaxBurstSize = 0;\r
2289 InputContext->EP[0].Interval = 0;\r
2290 InputContext->EP[0].MaxPStreams = 0;\r
2291 InputContext->EP[0].Mult = 0;\r
2292 InputContext->EP[0].CErr = 3;\r
2293\r
2294 //\r
2295 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2296 //\r
2297 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2298 Xhc->MemPool,\r
2299 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2300 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2301 );\r
2302 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2303 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2304\r
2305 //\r
2306 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2307 //\r
2308 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));\r
2309 ASSERT (OutputContext != NULL);\r
2310 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2311 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2312\r
2313 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
2314 //\r
2315 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2316 // a pointer to the Output Device Context data structure (6.2.1).\r
2317 //\r
2318 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2319 //\r
2320 // Fill DCBAA with PCI device address\r
2321 //\r
2322 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
2323\r
2324 //\r
2325 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2326 // Context data structure described above.\r
2327 //\r
2328 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2329 // to device.\r
2330 //\r
2331 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
2332 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
2333 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
2334 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2335 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2336 CmdTrbAddr.CycleBit = 1;\r
2337 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
2338 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2339 Status = XhcCmdTransfer (\r
2340 Xhc,\r
2341 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
2342 XHC_GENERIC_TIMEOUT,\r
2343 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2344 );\r
2345 if (!EFI_ERROR (Status)) {\r
2346 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;\r
2347 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2348 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2349 }\r
2350 return Status;\r
2351}\r
2352\r
2353\r
2354/**\r
2355 Disable the specified device slot.\r
2356\r
2357 @param Xhc The XHCI Instance.\r
2358 @param SlotId The slot id to be disabled.\r
2359\r
2360 @retval EFI_SUCCESS Successfully disable the device slot.\r
2361\r
2362**/\r
2363EFI_STATUS\r
2364EFIAPI\r
2365XhcDisableSlotCmd (\r
2366 IN USB_XHCI_INSTANCE *Xhc,\r
2367 IN UINT8 SlotId\r
2368 )\r
2369{\r
2370 EFI_STATUS Status;\r
2371 TRB_TEMPLATE *EvtTrb;\r
2372 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2373 UINT8 Index;\r
2374 VOID *RingSeg;\r
2375\r
2376 //\r
2377 // Disable the device slots occupied by these devices on its downstream ports.\r
2378 // Entry 0 is reserved.\r
2379 //\r
2380 for (Index = 0; Index < 255; Index++) {\r
2381 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2382 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2383 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2384 continue;\r
2385 }\r
2386\r
2387 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2388\r
2389 if (EFI_ERROR (Status)) {\r
2390 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2391 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2392 }\r
2393 }\r
2394\r
2395 //\r
2396 // Construct the disable slot command\r
2397 //\r
2398 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
2399\r
2400 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2401 CmdTrbDisSlot.CycleBit = 1;\r
2402 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2403 CmdTrbDisSlot.SlotId = SlotId;\r
2404 Status = XhcCmdTransfer (\r
2405 Xhc,\r
2406 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2407 XHC_GENERIC_TIMEOUT,\r
2408 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2409 );\r
2410 if (EFI_ERROR (Status)) {\r
2411 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2412 return Status;\r
2413 }\r
2414 //\r
2415 // Free the slot's device context entry\r
2416 //\r
2417 Xhc->DCBAA[SlotId] = 0;\r
2418\r
2419 //\r
2420 // Free the slot related data structure\r
2421 //\r
2422 for (Index = 0; Index < 31; Index++) {\r
2423 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2424 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2425 if (RingSeg != NULL) {\r
2426 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
2427 }\r
2428 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
2429 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
2430 }\r
2431 }\r
2432\r
2433 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2434 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2435 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2436 }\r
2437 }\r
2438\r
2439 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2440 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2441 }\r
2442\r
2443 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
2444 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
2445 }\r
2446\r
2447 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
2448 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
2449 }\r
2450 //\r
2451 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2452 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2453 // remove urb from XHCI's asynchronous transfer list.\r
2454 //\r
2455 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2456 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2457\r
2458 return Status;\r
2459}\r
2460\r
2461/**\r
2462 Disable the specified device slot.\r
2463\r
2464 @param Xhc The XHCI Instance.\r
2465 @param SlotId The slot id to be disabled.\r
2466\r
2467 @retval EFI_SUCCESS Successfully disable the device slot.\r
2468\r
2469**/\r
2470EFI_STATUS\r
2471EFIAPI\r
2472XhcDisableSlotCmd64 (\r
2473 IN USB_XHCI_INSTANCE *Xhc,\r
2474 IN UINT8 SlotId\r
2475 )\r
2476{\r
2477 EFI_STATUS Status;\r
2478 TRB_TEMPLATE *EvtTrb;\r
2479 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2480 UINT8 Index;\r
2481 VOID *RingSeg;\r
2482\r
2483 //\r
2484 // Disable the device slots occupied by these devices on its downstream ports.\r
2485 // Entry 0 is reserved.\r
2486 //\r
2487 for (Index = 0; Index < 255; Index++) {\r
2488 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2489 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2490 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2491 continue;\r
2492 }\r
2493\r
2494 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2495\r
2496 if (EFI_ERROR (Status)) {\r
2497 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2498 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2499 }\r
2500 }\r
2501\r
2502 //\r
2503 // Construct the disable slot command\r
2504 //\r
2505 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
2506\r
2507 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2508 CmdTrbDisSlot.CycleBit = 1;\r
2509 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2510 CmdTrbDisSlot.SlotId = SlotId;\r
2511 Status = XhcCmdTransfer (\r
2512 Xhc,\r
2513 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2514 XHC_GENERIC_TIMEOUT,\r
2515 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2516 );\r
2517 if (EFI_ERROR (Status)) {\r
2518 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2519 return Status;\r
2520 }\r
2521 //\r
2522 // Free the slot's device context entry\r
2523 //\r
2524 Xhc->DCBAA[SlotId] = 0;\r
2525\r
2526 //\r
2527 // Free the slot related data structure\r
2528 //\r
2529 for (Index = 0; Index < 31; Index++) {\r
2530 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2531 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2532 if (RingSeg != NULL) {\r
2533 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
2534 }\r
2535 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
2536 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
2537 }\r
2538 }\r
2539\r
2540 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2541 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2542 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2543 }\r
2544 }\r
2545\r
2546 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2547 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2548 }\r
2549\r
2550 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
2551 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
2552 }\r
2553\r
2554 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
2555 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2556 }\r
2557 //\r
2558 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2559 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2560 // remove urb from XHCI's asynchronous transfer list.\r
2561 //\r
2562 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2563 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2564\r
2565 return Status;\r
2566}\r
2567\r
2568/**\r
2569 Initialize endpoint context in input context.\r
2570\r
2571 @param Xhc The XHCI Instance.\r
2572 @param SlotId The slot id to be configured.\r
2573 @param DeviceSpeed The device's speed.\r
2574 @param InputContext The pointer to the input context.\r
2575 @param IfDesc The pointer to the usb device interface descriptor.\r
2576\r
2577 @return The maximum device context index of endpoint.\r
2578\r
2579**/\r
2580UINT8\r
2581EFIAPI\r
2582XhcInitializeEndpointContext (\r
2583 IN USB_XHCI_INSTANCE *Xhc,\r
2584 IN UINT8 SlotId,\r
2585 IN UINT8 DeviceSpeed,\r
2586 IN INPUT_CONTEXT *InputContext,\r
2587 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2588 )\r
2589{\r
2590 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2591 UINTN NumEp;\r
2592 UINTN EpIndex;\r
2593 UINT8 EpAddr;\r
2594 UINT8 Direction;\r
2595 UINT8 Dci;\r
2596 UINT8 MaxDci;\r
2597 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2598 UINT8 Interval;\r
2599 TRANSFER_RING *EndpointTransferRing;\r
2600\r
2601 MaxDci = 0;\r
2602\r
2603 NumEp = IfDesc->NumEndpoints;\r
2604\r
2605 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2606 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2607 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2608 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2609 }\r
2610\r
2611 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
2612 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2613 continue;\r
2614 }\r
2615\r
2616 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2617 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2618\r
2619 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2620 ASSERT (Dci < 32);\r
2621 if (Dci > MaxDci) {\r
2622 MaxDci = Dci;\r
2623 }\r
2624\r
2625 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2626 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2627\r
2628 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2629 //\r
2630 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2631 //\r
2632 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2633 } else {\r
2634 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2635 }\r
2636\r
2637 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2638 case USB_ENDPOINT_BULK:\r
2639 if (Direction == EfiUsbDataIn) {\r
2640 InputContext->EP[Dci-1].CErr = 3;\r
2641 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2642 } else {\r
2643 InputContext->EP[Dci-1].CErr = 3;\r
2644 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2645 }\r
2646\r
2647 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2648 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2649 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2650 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2651 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2652 }\r
2653\r
2654 break;\r
2655 case USB_ENDPOINT_ISO:\r
2656 if (Direction == EfiUsbDataIn) {\r
2657 InputContext->EP[Dci-1].CErr = 0;\r
2658 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2659 } else {\r
2660 InputContext->EP[Dci-1].CErr = 0;\r
2661 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2662 }\r
2663 //\r
2664 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
2665 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
2666 //\r
2667 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
2668 Interval = EpDesc->Interval;\r
2669 ASSERT (Interval >= 1 && Interval <= 16);\r
2670 InputContext->EP[Dci-1].Interval = Interval + 2;\r
2671 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2672 Interval = EpDesc->Interval;\r
2673 ASSERT (Interval >= 1 && Interval <= 16);\r
2674 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2675 }\r
2676\r
2677 //\r
2678 // Do not support isochronous transfer now.\r
2679 //\r
2680 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
2681 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2682 continue;\r
2683 case USB_ENDPOINT_INTERRUPT:\r
2684 if (Direction == EfiUsbDataIn) {\r
2685 InputContext->EP[Dci-1].CErr = 3;\r
2686 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2687 } else {\r
2688 InputContext->EP[Dci-1].CErr = 3;\r
2689 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2690 }\r
2691 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2692 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2693 //\r
2694 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2695 //\r
2696 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2697 Interval = EpDesc->Interval;\r
2698 //\r
2699 // Calculate through the bInterval field of Endpoint descriptor.\r
2700 //\r
2701 ASSERT (Interval != 0);\r
2702 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;\r
2703 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2704 Interval = EpDesc->Interval;\r
2705 ASSERT (Interval >= 1 && Interval <= 16);\r
2706 //\r
2707 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2708 //\r
2709 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2710 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2711 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2712 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2713 InputContext->EP[Dci-1].CErr = 3;\r
2714 }\r
2715\r
2716 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2717 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2718 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2719 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2720 }\r
2721 break;\r
2722\r
2723 case USB_ENDPOINT_CONTROL:\r
2724 //\r
2725 // Do not support control transfer now.\r
2726 //\r
2727 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
2728 default:\r
2729 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));\r
2730 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2731 continue;\r
2732 }\r
2733\r
2734 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2735 Xhc->MemPool,\r
2736 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2737 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2738 );\r
2739 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
2740 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
2741 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2742 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2743\r
2744 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2745 }\r
2746\r
2747 return MaxDci;\r
2748}\r
2749\r
2750/**\r
2751 Initialize endpoint context in input context.\r
2752\r
2753 @param Xhc The XHCI Instance.\r
2754 @param SlotId The slot id to be configured.\r
2755 @param DeviceSpeed The device's speed.\r
2756 @param InputContext The pointer to the input context.\r
2757 @param IfDesc The pointer to the usb device interface descriptor.\r
2758\r
2759 @return The maximum device context index of endpoint.\r
2760\r
2761**/\r
2762UINT8\r
2763EFIAPI\r
2764XhcInitializeEndpointContext64 (\r
2765 IN USB_XHCI_INSTANCE *Xhc,\r
2766 IN UINT8 SlotId,\r
2767 IN UINT8 DeviceSpeed,\r
2768 IN INPUT_CONTEXT_64 *InputContext,\r
2769 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2770 )\r
2771{\r
2772 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2773 UINTN NumEp;\r
2774 UINTN EpIndex;\r
2775 UINT8 EpAddr;\r
2776 UINT8 Direction;\r
2777 UINT8 Dci;\r
2778 UINT8 MaxDci;\r
2779 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2780 UINT8 Interval;\r
2781 TRANSFER_RING *EndpointTransferRing;\r
2782\r
2783 MaxDci = 0;\r
2784\r
2785 NumEp = IfDesc->NumEndpoints;\r
2786\r
2787 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2788 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2789 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2790 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2791 }\r
2792\r
2793 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
2794 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2795 continue;\r
2796 }\r
2797\r
2798 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2799 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2800\r
2801 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2802 ASSERT (Dci < 32);\r
2803 if (Dci > MaxDci) {\r
2804 MaxDci = Dci;\r
2805 }\r
2806\r
2807 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2808 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2809\r
2810 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2811 //\r
2812 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2813 //\r
2814 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2815 } else {\r
2816 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2817 }\r
2818\r
2819 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2820 case USB_ENDPOINT_BULK:\r
2821 if (Direction == EfiUsbDataIn) {\r
2822 InputContext->EP[Dci-1].CErr = 3;\r
2823 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2824 } else {\r
2825 InputContext->EP[Dci-1].CErr = 3;\r
2826 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2827 }\r
2828\r
2829 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2830 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2831 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2832 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2833 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2834 }\r
2835\r
2836 break;\r
2837 case USB_ENDPOINT_ISO:\r
2838 if (Direction == EfiUsbDataIn) {\r
2839 InputContext->EP[Dci-1].CErr = 0;\r
2840 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2841 } else {\r
2842 InputContext->EP[Dci-1].CErr = 0;\r
2843 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2844 }\r
2845 //\r
2846 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
2847 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
2848 //\r
2849 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
2850 Interval = EpDesc->Interval;\r
2851 ASSERT (Interval >= 1 && Interval <= 16);\r
2852 InputContext->EP[Dci-1].Interval = Interval + 2;\r
2853 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2854 Interval = EpDesc->Interval;\r
2855 ASSERT (Interval >= 1 && Interval <= 16);\r
2856 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2857 }\r
2858\r
2859 //\r
2860 // Do not support isochronous transfer now.\r
2861 //\r
2862 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
2863 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2864 continue;\r
2865 case USB_ENDPOINT_INTERRUPT:\r
2866 if (Direction == EfiUsbDataIn) {\r
2867 InputContext->EP[Dci-1].CErr = 3;\r
2868 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2869 } else {\r
2870 InputContext->EP[Dci-1].CErr = 3;\r
2871 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2872 }\r
2873 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2874 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2875 //\r
2876 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2877 //\r
2878 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2879 Interval = EpDesc->Interval;\r
2880 //\r
2881 // Calculate through the bInterval field of Endpoint descriptor.\r
2882 //\r
2883 ASSERT (Interval != 0);\r
2884 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;\r
2885 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2886 Interval = EpDesc->Interval;\r
2887 ASSERT (Interval >= 1 && Interval <= 16);\r
2888 //\r
2889 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2890 //\r
2891 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2892 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2893 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2894 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2895 InputContext->EP[Dci-1].CErr = 3;\r
2896 }\r
2897\r
2898 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2899 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2900 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2901 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2902 }\r
2903 break;\r
2904\r
2905 case USB_ENDPOINT_CONTROL:\r
2906 //\r
2907 // Do not support control transfer now.\r
2908 //\r
2909 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
2910 default:\r
2911 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));\r
2912 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2913 continue;\r
2914 }\r
2915\r
2916 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2917 Xhc->MemPool,\r
2918 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2919 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2920 );\r
2921 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
2922 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
2923 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2924 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2925\r
2926 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2927 }\r
2928\r
2929 return MaxDci;\r
2930}\r
2931\r
2932/**\r
2933 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
2934\r
2935 @param Xhc The XHCI Instance.\r
2936 @param SlotId The slot id to be configured.\r
2937 @param DeviceSpeed The device's speed.\r
2938 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
2939\r
2940 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
2941\r
2942**/\r
2943EFI_STATUS\r
2944EFIAPI\r
2945XhcSetConfigCmd (\r
2946 IN USB_XHCI_INSTANCE *Xhc,\r
2947 IN UINT8 SlotId,\r
2948 IN UINT8 DeviceSpeed,\r
2949 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
2950 )\r
2951{\r
2952 EFI_STATUS Status;\r
2953 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
2954 UINT8 Index;\r
2955 UINT8 Dci;\r
2956 UINT8 MaxDci;\r
2957 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2958\r
2959 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
2960 INPUT_CONTEXT *InputContext;\r
2961 DEVICE_CONTEXT *OutputContext;\r
2962 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2963 //\r
2964 // 4.6.6 Configure Endpoint\r
2965 //\r
2966 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2967 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
2968 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2969 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
2970\r
2971 ASSERT (ConfigDesc != NULL);\r
2972\r
2973 MaxDci = 0;\r
2974\r
2975 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
2976 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
2977 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
2978 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2979 }\r
2980\r
2981 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
2982 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2983 continue;\r
2984 }\r
2985\r
2986 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
2987 if (Dci > MaxDci) {\r
2988 MaxDci = Dci;\r
2989 }\r
2990\r
2991 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2992 }\r
2993\r
2994 InputContext->InputControlContext.Dword2 |= BIT0;\r
2995 InputContext->Slot.ContextEntries = MaxDci;\r
2996 //\r
2997 // configure endpoint\r
2998 //\r
2999 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3000 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3001 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3002 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3003 CmdTrbCfgEP.CycleBit = 1;\r
3004 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3005 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3006 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
3007 Status = XhcCmdTransfer (\r
3008 Xhc,\r
3009 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3010 XHC_GENERIC_TIMEOUT,\r
3011 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3012 );\r
3013 if (EFI_ERROR (Status)) {\r
3014 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
3015 } else {\r
3016 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
3017 }\r
3018\r
3019 return Status;\r
3020}\r
3021\r
3022/**\r
3023 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
3024\r
3025 @param Xhc The XHCI Instance.\r
3026 @param SlotId The slot id to be configured.\r
3027 @param DeviceSpeed The device's speed.\r
3028 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3029\r
3030 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
3031\r
3032**/\r
3033EFI_STATUS\r
3034EFIAPI\r
3035XhcSetConfigCmd64 (\r
3036 IN USB_XHCI_INSTANCE *Xhc,\r
3037 IN UINT8 SlotId,\r
3038 IN UINT8 DeviceSpeed,\r
3039 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
3040 )\r
3041{\r
3042 EFI_STATUS Status;\r
3043 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3044 UINT8 Index;\r
3045 UINT8 Dci;\r
3046 UINT8 MaxDci;\r
3047 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3048\r
3049 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3050 INPUT_CONTEXT_64 *InputContext;\r
3051 DEVICE_CONTEXT_64 *OutputContext;\r
3052 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3053 //\r
3054 // 4.6.6 Configure Endpoint\r
3055 //\r
3056 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3057 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3058 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3059 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
3060\r
3061 ASSERT (ConfigDesc != NULL);\r
3062\r
3063 MaxDci = 0;\r
3064\r
3065 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3066 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
3067 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
3068 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3069 }\r
3070\r
3071 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
3072 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3073 continue;\r
3074 }\r
3075\r
3076 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
3077 if (Dci > MaxDci) {\r
3078 MaxDci = Dci;\r
3079 }\r
3080 \r
3081 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3082 }\r
3083\r
3084 InputContext->InputControlContext.Dword2 |= BIT0;\r
3085 InputContext->Slot.ContextEntries = MaxDci;\r
3086 //\r
3087 // configure endpoint\r
3088 //\r
3089 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3090 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3091 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3092 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3093 CmdTrbCfgEP.CycleBit = 1;\r
3094 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3095 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3096 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
3097 Status = XhcCmdTransfer (\r
3098 Xhc,\r
3099 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3100 XHC_GENERIC_TIMEOUT,\r
3101 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3102 );\r
3103 if (EFI_ERROR (Status)) {\r
3104 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
3105 } else {\r
3106 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
3107 }\r
3108\r
3109 return Status;\r
3110}\r
3111\r
3112/**\r
3113 Stop endpoint through XHCI's Stop_Endpoint cmd.\r
3114\r
3115 @param Xhc The XHCI Instance.\r
3116 @param SlotId The slot id to be configured.\r
3117 @param Dci The device context index of endpoint.\r
3118\r
3119 @retval EFI_SUCCESS Stop endpoint successfully.\r
3120 @retval Others Failed to stop endpoint.\r
3121\r
3122**/\r
3123EFI_STATUS\r
3124EFIAPI\r
3125XhcStopEndpoint (\r
3126 IN USB_XHCI_INSTANCE *Xhc,\r
3127 IN UINT8 SlotId,\r
3128 IN UINT8 Dci\r
3129 )\r
3130{\r
3131 EFI_STATUS Status;\r
3132 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3133 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;\r
3134\r
3135 DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
3136\r
3137 //\r
3138 // Send stop endpoint command to transit Endpoint from running to stop state\r
3139 //\r
3140 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));\r
3141 CmdTrbStopED.CycleBit = 1;\r
3142 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;\r
3143 CmdTrbStopED.EDID = Dci;\r
3144 CmdTrbStopED.SlotId = SlotId;\r
3145 Status = XhcCmdTransfer (\r
3146 Xhc,\r
3147 (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,\r
3148 XHC_GENERIC_TIMEOUT,\r
3149 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3150 );\r
3151 if (EFI_ERROR(Status)) {\r
3152 DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
3153 }\r
3154\r
3155 return Status;\r
3156}\r
3157\r
3158/**\r
3159 Reset endpoint through XHCI's Reset_Endpoint cmd.\r
3160\r
3161 @param Xhc The XHCI Instance.\r
3162 @param SlotId The slot id to be configured.\r
3163 @param Dci The device context index of endpoint.\r
3164\r
3165 @retval EFI_SUCCESS Reset endpoint successfully.\r
3166 @retval Others Failed to reset endpoint.\r
3167\r
3168**/\r
3169EFI_STATUS\r
3170EFIAPI\r
3171XhcResetEndpoint (\r
3172 IN USB_XHCI_INSTANCE *Xhc,\r
3173 IN UINT8 SlotId,\r
3174 IN UINT8 Dci\r
3175 )\r
3176{\r
3177 EFI_STATUS Status;\r
3178 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3179 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
3180\r
3181 DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
3182\r
3183 //\r
3184 // Send stop endpoint command to transit Endpoint from running to stop state\r
3185 //\r
3186 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
3187 CmdTrbResetED.CycleBit = 1;\r
3188 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
3189 CmdTrbResetED.EDID = Dci;\r
3190 CmdTrbResetED.SlotId = SlotId;\r
3191 Status = XhcCmdTransfer (\r
3192 Xhc,\r
3193 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
3194 XHC_GENERIC_TIMEOUT,\r
3195 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3196 );\r
3197 if (EFI_ERROR(Status)) {\r
3198 DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
3199 }\r
3200\r
3201 return Status;\r
3202}\r
3203\r
3204/**\r
3205 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
3206\r
3207 @param Xhc The XHCI Instance.\r
3208 @param SlotId The slot id to be configured.\r
3209 @param Dci The device context index of endpoint.\r
3210 @param Urb The dequeue pointer of the transfer ring specified\r
3211 by the urb to be updated.\r
3212\r
3213 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.\r
3214 @retval Others Failed to set transfer ring dequeue pointer.\r
3215\r
3216**/\r
3217EFI_STATUS\r
3218EFIAPI\r
3219XhcSetTrDequeuePointer (\r
3220 IN USB_XHCI_INSTANCE *Xhc,\r
3221 IN UINT8 SlotId,\r
3222 IN UINT8 Dci,\r
3223 IN URB *Urb\r
3224 )\r
3225{\r
3226 EFI_STATUS Status;\r
3227 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3228 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
3229 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3230\r
3231 DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
3232\r
3233 //\r
3234 // Send stop endpoint command to transit Endpoint from running to stop state\r
3235 //\r
3236 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
3237 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
3238 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
3239 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3240 CmdSetTRDeq.CycleBit = 1;\r
3241 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
3242 CmdSetTRDeq.Endpoint = Dci;\r
3243 CmdSetTRDeq.SlotId = SlotId;\r
3244 Status = XhcCmdTransfer (\r
3245 Xhc,\r
3246 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
3247 XHC_GENERIC_TIMEOUT,\r
3248 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3249 );\r
3250 if (EFI_ERROR(Status)) {\r
3251 DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
3252 }\r
3253\r
3254 return Status;\r
3255}\r
3256\r
3257/**\r
3258 Set interface through XHCI's Configure_Endpoint cmd.\r
3259\r
3260 @param Xhc The XHCI Instance.\r
3261 @param SlotId The slot id to be configured.\r
3262 @param DeviceSpeed The device's speed.\r
3263 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3264 @param Request USB device request to send.\r
3265\r
3266 @retval EFI_SUCCESS Successfully set interface.\r
3267\r
3268**/\r
3269EFI_STATUS\r
3270EFIAPI\r
3271XhcSetInterface (\r
3272 IN USB_XHCI_INSTANCE *Xhc,\r
3273 IN UINT8 SlotId,\r
3274 IN UINT8 DeviceSpeed,\r
3275 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3276 IN EFI_USB_DEVICE_REQUEST *Request\r
3277 )\r
3278{\r
3279 EFI_STATUS Status;\r
3280 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3281 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3282 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3283 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3284 UINTN NumEp;\r
3285 UINTN EpIndex;\r
3286 UINT8 EpAddr;\r
3287 UINT8 Direction;\r
3288 UINT8 Dci;\r
3289 UINT8 MaxDci;\r
3290 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3291 VOID *RingSeg;\r
3292\r
3293 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3294 INPUT_CONTEXT *InputContext;\r
3295 DEVICE_CONTEXT *OutputContext;\r
3296 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3297\r
3298 Status = EFI_SUCCESS;\r
3299\r
3300 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3301 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3302 //\r
3303 // XHCI 4.6.6 Configure Endpoint\r
3304 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3305 // Context and Add Context flags as follows:\r
3306 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3307 // Context and Add Context flags to '0'.\r
3308 //\r
3309 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3310 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3311 //\r
3312 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3313 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
3314\r
3315 ASSERT (ConfigDesc != NULL);\r
3316\r
3317 MaxDci = 0;\r
3318\r
3319 IfDescActive = NULL;\r
3320 IfDescSet = NULL;\r
3321\r
3322 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3323 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
3324 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
3325 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
3326 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3327 //\r
3328 // Find out the active interface descriptor.\r
3329 //\r
3330 IfDescActive = IfDesc;\r
3331 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {\r
3332 //\r
3333 // Find out the interface descriptor to set.\r
3334 //\r
3335 IfDescSet = IfDesc;\r
3336 }\r
3337 }\r
3338 }\r
3339 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3340 }\r
3341\r
3342 //\r
3343 // XHCI 4.6.6 Configure Endpoint\r
3344 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3345 // Context and Add Context flags as follows:\r
3346 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3347 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3348 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3349 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3350 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3351 // and Add Context flags shall be set to '1'.\r
3352 //\r
3353 // Below codes are to cover 2), 3) and 4).\r
3354 //\r
3355\r
3356 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3357 NumEp = IfDescActive->NumEndpoints;\r
3358 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);\r
3359 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3360 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3361 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3362 }\r
3363\r
3364 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3365 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3366 continue;\r
3367 }\r
3368\r
3369 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
3370 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3371\r
3372 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3373 ASSERT (Dci < 32);\r
3374 if (Dci > MaxDci) {\r
3375 MaxDci = Dci;\r
3376 }\r
3377 //\r
3378 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3379 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3380 //\r
3381 Status = XhcStopEndpoint (Xhc, SlotId, Dci);\r
3382 if (EFI_ERROR (Status)) {\r
3383 return Status;\r
3384 }\r
3385 //\r
3386 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3387 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3388 //\r
3389 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3390 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3391 if (RingSeg != NULL) {\r
3392 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3393 }\r
3394 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3395 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3396 }\r
3397\r
3398 //\r
3399 // Set the Drop Context flag to '1'.\r
3400 //\r
3401 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3402\r
3403 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3404 }\r
3405\r
3406 //\r
3407 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3408 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3409 // Interface setting, to '0'.\r
3410 //\r
3411 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3412 //\r
3413\r
3414 //\r
3415 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3416 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3417 // a. Allocate a Transfer Ring.\r
3418 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3419 // c. Initialize the Endpoint Context data structure.\r
3420 //\r
3421 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3422 if (Dci > MaxDci) {\r
3423 MaxDci = Dci;\r
3424 }\r
3425\r
3426 InputContext->InputControlContext.Dword2 |= BIT0;\r
3427 InputContext->Slot.ContextEntries = MaxDci;\r
3428 //\r
3429 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3430 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3431 //\r
3432 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3433 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3434 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3435 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3436 CmdTrbCfgEP.CycleBit = 1;\r
3437 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3438 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3439 DEBUG ((EFI_D_INFO, "SetInterface: Configure Endpoint\n"));\r
3440 Status = XhcCmdTransfer (\r
3441 Xhc,\r
3442 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3443 XHC_GENERIC_TIMEOUT,\r
3444 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3445 );\r
3446 if (EFI_ERROR (Status)) {\r
3447 DEBUG ((EFI_D_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));\r
3448 } else {\r
3449 //\r
3450 // Update the active AlternateSetting.\r
3451 //\r
3452 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;\r
3453 }\r
3454 }\r
3455\r
3456 return Status;\r
3457}\r
3458\r
3459/**\r
3460 Set interface through XHCI's Configure_Endpoint cmd.\r
3461\r
3462 @param Xhc The XHCI Instance.\r
3463 @param SlotId The slot id to be configured.\r
3464 @param DeviceSpeed The device's speed.\r
3465 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3466 @param Request USB device request to send.\r
3467\r
3468 @retval EFI_SUCCESS Successfully set interface.\r
3469\r
3470**/\r
3471EFI_STATUS\r
3472EFIAPI\r
3473XhcSetInterface64 (\r
3474 IN USB_XHCI_INSTANCE *Xhc,\r
3475 IN UINT8 SlotId,\r
3476 IN UINT8 DeviceSpeed,\r
3477 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3478 IN EFI_USB_DEVICE_REQUEST *Request\r
3479 )\r
3480{\r
3481 EFI_STATUS Status;\r
3482 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3483 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3484 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3485 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3486 UINTN NumEp;\r
3487 UINTN EpIndex;\r
3488 UINT8 EpAddr;\r
3489 UINT8 Direction;\r
3490 UINT8 Dci;\r
3491 UINT8 MaxDci;\r
3492 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3493 VOID *RingSeg;\r
3494\r
3495 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3496 INPUT_CONTEXT_64 *InputContext;\r
3497 DEVICE_CONTEXT_64 *OutputContext;\r
3498 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3499\r
3500 Status = EFI_SUCCESS;\r
3501\r
3502 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3503 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3504 //\r
3505 // XHCI 4.6.6 Configure Endpoint\r
3506 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3507 // Context and Add Context flags as follows:\r
3508 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3509 // Context and Add Context flags to '0'.\r
3510 //\r
3511 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3512 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3513 //\r
3514 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3515 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
3516\r
3517 ASSERT (ConfigDesc != NULL);\r
3518\r
3519 MaxDci = 0;\r
3520\r
3521 IfDescActive = NULL;\r
3522 IfDescSet = NULL;\r
3523\r
3524 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3525 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
3526 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
3527 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
3528 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3529 //\r
3530 // Find out the active interface descriptor.\r
3531 //\r
3532 IfDescActive = IfDesc;\r
3533 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {\r
3534 //\r
3535 // Find out the interface descriptor to set.\r
3536 //\r
3537 IfDescSet = IfDesc;\r
3538 }\r
3539 }\r
3540 }\r
3541 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3542 }\r
3543\r
3544 //\r
3545 // XHCI 4.6.6 Configure Endpoint\r
3546 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3547 // Context and Add Context flags as follows:\r
3548 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3549 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3550 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3551 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3552 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3553 // and Add Context flags shall be set to '1'.\r
3554 //\r
3555 // Below codes are to cover 2), 3) and 4).\r
3556 //\r
3557\r
3558 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3559 NumEp = IfDescActive->NumEndpoints;\r
3560 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);\r
3561 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3562 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3563 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3564 }\r
3565\r
3566 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3567 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3568 continue;\r
3569 }\r
3570\r
3571 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
3572 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3573\r
3574 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3575 ASSERT (Dci < 32);\r
3576 if (Dci > MaxDci) {\r
3577 MaxDci = Dci;\r
3578 }\r
3579 //\r
3580 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3581 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3582 //\r
3583 Status = XhcStopEndpoint (Xhc, SlotId, Dci);\r
3584 if (EFI_ERROR (Status)) {\r
3585 return Status;\r
3586 }\r
3587 //\r
3588 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3589 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3590 //\r
3591 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3592 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3593 if (RingSeg != NULL) {\r
3594 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3595 }\r
3596 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3597 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3598 }\r
3599\r
3600 //\r
3601 // Set the Drop Context flag to '1'.\r
3602 //\r
3603 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3604\r
3605 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3606 }\r
3607\r
3608 //\r
3609 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3610 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3611 // Interface setting, to '0'.\r
3612 //\r
3613 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3614 //\r
3615\r
3616 //\r
3617 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3618 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3619 // a. Allocate a Transfer Ring.\r
3620 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3621 // c. Initialize the Endpoint Context data structure.\r
3622 //\r
3623 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3624 if (Dci > MaxDci) {\r
3625 MaxDci = Dci;\r
3626 }\r
3627\r
3628 InputContext->InputControlContext.Dword2 |= BIT0;\r
3629 InputContext->Slot.ContextEntries = MaxDci;\r
3630 //\r
3631 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3632 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3633 //\r
3634 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3635 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3636 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3637 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3638 CmdTrbCfgEP.CycleBit = 1;\r
3639 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3640 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3641 DEBUG ((EFI_D_INFO, "SetInterface64: Configure Endpoint\n"));\r
3642 Status = XhcCmdTransfer (\r
3643 Xhc,\r
3644 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3645 XHC_GENERIC_TIMEOUT,\r
3646 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3647 );\r
3648 if (EFI_ERROR (Status)) {\r
3649 DEBUG ((EFI_D_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));\r
3650 } else {\r
3651 //\r
3652 // Update the active AlternateSetting.\r
3653 //\r
3654 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;\r
3655 }\r
3656 }\r
3657\r
3658 return Status;\r
3659}\r
3660\r
3661/**\r
3662 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
3663\r
3664 @param Xhc The XHCI Instance.\r
3665 @param SlotId The slot id to be evaluated.\r
3666 @param MaxPacketSize The max packet size supported by the device control transfer.\r
3667\r
3668 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
3669\r
3670**/\r
3671EFI_STATUS\r
3672EFIAPI\r
3673XhcEvaluateContext (\r
3674 IN USB_XHCI_INSTANCE *Xhc,\r
3675 IN UINT8 SlotId,\r
3676 IN UINT32 MaxPacketSize\r
3677 )\r
3678{\r
3679 EFI_STATUS Status;\r
3680 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
3681 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3682 INPUT_CONTEXT *InputContext;\r
3683 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3684\r
3685 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3686\r
3687 //\r
3688 // 4.6.7 Evaluate Context\r
3689 //\r
3690 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3691 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3692\r
3693 InputContext->InputControlContext.Dword2 |= BIT1;\r
3694 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
3695\r
3696 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
3697 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3698 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3699 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3700 CmdTrbEvalu.CycleBit = 1;\r
3701 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
3702 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3703 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
3704 Status = XhcCmdTransfer (\r
3705 Xhc,\r
3706 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
3707 XHC_GENERIC_TIMEOUT,\r
3708 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3709 );\r
3710 if (EFI_ERROR (Status)) {\r
3711 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
3712 }\r
3713 return Status;\r
3714}\r
3715\r
3716/**\r
3717 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
3718\r
3719 @param Xhc The XHCI Instance.\r
3720 @param SlotId The slot id to be evaluated.\r
3721 @param MaxPacketSize The max packet size supported by the device control transfer.\r
3722\r
3723 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
3724\r
3725**/\r
3726EFI_STATUS\r
3727EFIAPI\r
3728XhcEvaluateContext64 (\r
3729 IN USB_XHCI_INSTANCE *Xhc,\r
3730 IN UINT8 SlotId,\r
3731 IN UINT32 MaxPacketSize\r
3732 )\r
3733{\r
3734 EFI_STATUS Status;\r
3735 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
3736 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3737 INPUT_CONTEXT_64 *InputContext;\r
3738 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3739\r
3740 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3741\r
3742 //\r
3743 // 4.6.7 Evaluate Context\r
3744 //\r
3745 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3746 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3747\r
3748 InputContext->InputControlContext.Dword2 |= BIT1;\r
3749 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
3750\r
3751 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
3752 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3753 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3754 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3755 CmdTrbEvalu.CycleBit = 1;\r
3756 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
3757 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3758 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
3759 Status = XhcCmdTransfer (\r
3760 Xhc,\r
3761 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
3762 XHC_GENERIC_TIMEOUT,\r
3763 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3764 );\r
3765 if (EFI_ERROR (Status)) {\r
3766 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
3767 }\r
3768 return Status;\r
3769}\r
3770\r
3771\r
3772/**\r
3773 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
3774\r
3775 @param Xhc The XHCI Instance.\r
3776 @param SlotId The slot id to be configured.\r
3777 @param PortNum The total number of downstream port supported by the hub.\r
3778 @param TTT The TT think time of the hub device.\r
3779 @param MTT The multi-TT of the hub device.\r
3780\r
3781 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
3782\r
3783**/\r
3784EFI_STATUS\r
3785XhcConfigHubContext (\r
3786 IN USB_XHCI_INSTANCE *Xhc,\r
3787 IN UINT8 SlotId,\r
3788 IN UINT8 PortNum,\r
3789 IN UINT8 TTT,\r
3790 IN UINT8 MTT\r
3791 )\r
3792{\r
3793 EFI_STATUS Status;\r
3794 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3795 INPUT_CONTEXT *InputContext;\r
3796 DEVICE_CONTEXT *OutputContext;\r
3797 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3798 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3799\r
3800 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3801 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3802 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3803\r
3804 //\r
3805 // 4.6.7 Evaluate Context\r
3806 //\r
3807 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3808\r
3809 InputContext->InputControlContext.Dword2 |= BIT0;\r
3810\r
3811 //\r
3812 // Copy the slot context from OutputContext to Input context\r
3813 //\r
3814 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
3815 InputContext->Slot.Hub = 1;\r
3816 InputContext->Slot.PortNum = PortNum;\r
3817 InputContext->Slot.TTT = TTT;\r
3818 InputContext->Slot.MTT = MTT;\r
3819\r
3820 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3821 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3822 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3823 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3824 CmdTrbCfgEP.CycleBit = 1;\r
3825 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3826 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3827 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
3828 Status = XhcCmdTransfer (\r
3829 Xhc,\r
3830 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3831 XHC_GENERIC_TIMEOUT,\r
3832 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3833 );\r
3834 if (EFI_ERROR (Status)) {\r
3835 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
3836 }\r
3837 return Status;\r
3838}\r
3839\r
3840/**\r
3841 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
3842\r
3843 @param Xhc The XHCI Instance.\r
3844 @param SlotId The slot id to be configured.\r
3845 @param PortNum The total number of downstream port supported by the hub.\r
3846 @param TTT The TT think time of the hub device.\r
3847 @param MTT The multi-TT of the hub device.\r
3848\r
3849 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
3850\r
3851**/\r
3852EFI_STATUS\r
3853XhcConfigHubContext64 (\r
3854 IN USB_XHCI_INSTANCE *Xhc,\r
3855 IN UINT8 SlotId,\r
3856 IN UINT8 PortNum,\r
3857 IN UINT8 TTT,\r
3858 IN UINT8 MTT\r
3859 )\r
3860{\r
3861 EFI_STATUS Status;\r
3862 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3863 INPUT_CONTEXT_64 *InputContext;\r
3864 DEVICE_CONTEXT_64 *OutputContext;\r
3865 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3866 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3867\r
3868 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3869 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3870 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3871\r
3872 //\r
3873 // 4.6.7 Evaluate Context\r
3874 //\r
3875 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3876\r
3877 InputContext->InputControlContext.Dword2 |= BIT0;\r
3878\r
3879 //\r
3880 // Copy the slot context from OutputContext to Input context\r
3881 //\r
3882 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
3883 InputContext->Slot.Hub = 1;\r
3884 InputContext->Slot.PortNum = PortNum;\r
3885 InputContext->Slot.TTT = TTT;\r
3886 InputContext->Slot.MTT = MTT;\r
3887\r
3888 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3889 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3890 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3891 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3892 CmdTrbCfgEP.CycleBit = 1;\r
3893 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3894 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3895 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
3896 Status = XhcCmdTransfer (\r
3897 Xhc,\r
3898 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3899 XHC_GENERIC_TIMEOUT,\r
3900 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3901 );\r
3902 if (EFI_ERROR (Status)) {\r
3903 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
3904 }\r
3905 return Status;\r
3906}\r
3907\r
3908\r