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