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