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