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