]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
MdeModulePkg/Usb: Make sure data from HW is no more than expected
[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
1413/**\r
1414 Update the queue head for next round of asynchronous transfer\r
1415\r
a9292c13 1416 @param Xhc The XHCI Instance.\r
92870c98 1417 @param Urb The URB to update\r
1418\r
1419**/\r
1420VOID\r
1421XhcUpdateAsyncRequest (\r
a9292c13 1422 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1423 IN URB *Urb\r
1424 )\r
1425{\r
1426 EFI_STATUS Status;\r
1427\r
1428 if (Urb->Result == EFI_USB_NOERROR) {\r
1429 Status = XhcCreateTransferTrb (Xhc, Urb);\r
6b4483cd 1430 if (EFI_ERROR (Status)) {\r
1431 return;\r
1432 }\r
92870c98 1433 Status = RingIntTransferDoorBell (Xhc, Urb);\r
6b4483cd 1434 if (EFI_ERROR (Status)) {\r
1435 return;\r
1436 }\r
92870c98 1437 }\r
1438}\r
1439\r
1847ed0b
EL
1440/**\r
1441 Flush data from PCI controller specific address to mapped system\r
1442 memory address.\r
1443\r
1444 @param Xhc The XHCI device.\r
1445 @param Urb The URB to unmap.\r
1446\r
1447 @retval EFI_SUCCESS Success to flush data to mapped system memory.\r
1448 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.\r
1449\r
1450**/\r
1451EFI_STATUS\r
1452XhcFlushAsyncIntMap (\r
1453 IN USB_XHCI_INSTANCE *Xhc,\r
1454 IN URB *Urb\r
1455 )\r
1456{\r
1457 EFI_STATUS Status;\r
1458 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1459 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
1460 EFI_PCI_IO_PROTOCOL *PciIo;\r
1461 UINTN Len;\r
1462 VOID *Map;\r
1463\r
1464 PciIo = Xhc->PciIo;\r
1465 Len = Urb->DataLen;\r
1466\r
1467 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
1468 MapOp = EfiPciIoOperationBusMasterWrite;\r
1469 } else {\r
1470 MapOp = EfiPciIoOperationBusMasterRead;\r
1471 }\r
1472\r
1473 if (Urb->DataMap != NULL) {\r
1474 Status = PciIo->Unmap (PciIo, Urb->DataMap);\r
1475 if (EFI_ERROR (Status)) {\r
1476 goto ON_ERROR;\r
1477 }\r
1478 }\r
1479\r
1480 Urb->DataMap = NULL;\r
1481\r
1482 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
1483 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
1484 goto ON_ERROR;\r
1485 }\r
1486\r
1487 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
1488 Urb->DataMap = Map;\r
1489 return EFI_SUCCESS;\r
1490\r
1491ON_ERROR:\r
1492 return EFI_DEVICE_ERROR;\r
1493}\r
92870c98 1494\r
1495/**\r
1496 Interrupt transfer periodic check handler.\r
1497\r
1498 @param Event Interrupt event.\r
a9292c13 1499 @param Context Pointer to USB_XHCI_INSTANCE.\r
92870c98 1500\r
1501**/\r
1502VOID\r
1503EFIAPI\r
1504XhcMonitorAsyncRequests (\r
1505 IN EFI_EVENT Event,\r
1506 IN VOID *Context\r
1507 )\r
1508{\r
a9292c13 1509 USB_XHCI_INSTANCE *Xhc;\r
92870c98 1510 LIST_ENTRY *Entry;\r
1511 LIST_ENTRY *Next;\r
1512 UINT8 *ProcBuf;\r
1513 URB *Urb;\r
1514 UINT8 SlotId;\r
1847ed0b 1515 EFI_STATUS Status;\r
92870c98 1516 EFI_TPL OldTpl;\r
1517\r
1518 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1519\r
a9292c13 1520 Xhc = (USB_XHCI_INSTANCE*) Context;\r
92870c98 1521\r
1522 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1523 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1524\r
1525 //\r
1526 // Make sure that the device is available before every check.\r
1527 //\r
6b4483cd 1528 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
92870c98 1529 if (SlotId == 0) {\r
1530 continue;\r
1531 }\r
1532\r
1533 //\r
1534 // Check the result of URB execution. If it is still\r
1535 // active, check the next one.\r
1536 //\r
b6cb9c39 1537 XhcCheckUrbResult (Xhc, Urb);\r
92870c98 1538\r
a50f7c4c 1539 if (!Urb->Finished) {\r
92870c98 1540 continue;\r
1541 }\r
1542\r
1847ed0b
EL
1543 //\r
1544 // Flush any PCI posted write transactions from a PCI host\r
1545 // bridge to system memory.\r
1546 //\r
1547 Status = XhcFlushAsyncIntMap (Xhc, Urb);\r
1548 if (EFI_ERROR (Status)) {\r
1549 DEBUG ((EFI_D_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));\r
1550 }\r
1551\r
92870c98 1552 //\r
1553 // Allocate a buffer then copy the transferred data for user.\r
1554 // If failed to allocate the buffer, update the URB for next\r
1555 // round of transfer. Ignore the data of this round.\r
1556 //\r
1557 ProcBuf = NULL;\r
1558 if (Urb->Result == EFI_USB_NOERROR) {\r
7fb7259f
RN
1559 //\r
1560 // Make sure the data received from HW is no more than expected.\r
1561 //\r
1562 if (Urb->Completed <= Urb->DataLen) {\r
1563 ProcBuf = AllocateZeroPool (Urb->Completed);\r
1564 }\r
92870c98 1565\r
1566 if (ProcBuf == NULL) {\r
1567 XhcUpdateAsyncRequest (Xhc, Urb);\r
1568 continue;\r
1569 }\r
1570\r
1571 CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
1572 }\r
1573\r
92870c98 1574 //\r
1575 // Leave error recovery to its related device driver. A\r
1576 // common case of the error recovery is to re-submit the\r
1577 // interrupt transfer which is linked to the head of the\r
1578 // list. This function scans from head to tail. So the\r
1579 // re-submitted interrupt transfer's callback function\r
1580 // will not be called again in this round. Don't touch this\r
1581 // URB after the callback, it may have been removed by the\r
1582 // callback.\r
1583 //\r
1584 if (Urb->Callback != NULL) {\r
1585 //\r
1586 // Restore the old TPL, USB bus maybe connect device in\r
1587 // his callback. Some drivers may has a lower TPL restriction.\r
1588 //\r
1589 gBS->RestoreTPL (OldTpl);\r
1590 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
1591 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1592 }\r
1593\r
1594 if (ProcBuf != NULL) {\r
1595 gBS->FreePool (ProcBuf);\r
1596 }\r
a50f7c4c 1597\r
1598 XhcUpdateAsyncRequest (Xhc, Urb);\r
92870c98 1599 }\r
1600 gBS->RestoreTPL (OldTpl);\r
1601}\r
1602\r
1603/**\r
1604 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
1605\r
a9292c13 1606 @param Xhc The XHCI Instance.\r
92870c98 1607 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
1608 @param Port The port to be polled.\r
1609 @param PortState The port state.\r
1610\r
1611 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
1612 @retval Others Should not appear.\r
1613\r
1614**/\r
1615EFI_STATUS\r
1616EFIAPI\r
1617XhcPollPortStatusChange (\r
a9292c13 1618 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1619 IN USB_DEV_ROUTE ParentRouteChart,\r
1620 IN UINT8 Port,\r
1621 IN EFI_USB_PORT_STATUS *PortState\r
1622 )\r
1623{\r
1624 EFI_STATUS Status;\r
1625 UINT8 Speed;\r
1626 UINT8 SlotId;\r
1627 USB_DEV_ROUTE RouteChart;\r
1628\r
1629 Status = EFI_SUCCESS;\r
1630\r
c3f44a77
FT
1631 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
1632 return EFI_SUCCESS;\r
1633 }\r
1634\r
92870c98 1635 if (ParentRouteChart.Dword == 0) {\r
a9292c13 1636 RouteChart.Route.RouteString = 0;\r
1637 RouteChart.Route.RootPortNum = Port + 1;\r
1638 RouteChart.Route.TierNum = 1;\r
92870c98 1639 } else {\r
1640 if(Port < 14) {\r
a9292c13 1641 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1642 } else {\r
a9292c13 1643 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1644 }\r
a9292c13 1645 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
1646 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
92870c98 1647 }\r
1648\r
c3f44a77
FT
1649 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1650 if (SlotId != 0) {\r
1651 if (Xhc->HcCParams.Data.Csz == 0) {\r
1652 Status = XhcDisableSlotCmd (Xhc, SlotId);\r
1653 } else {\r
1654 Status = XhcDisableSlotCmd64 (Xhc, SlotId);\r
1655 }\r
1656 }\r
1657\r
92870c98 1658 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1659 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
1660 //\r
1661 // Has a device attached, Identify device speed after port is enabled.\r
1662 //\r
1663 Speed = EFI_USB_SPEED_FULL;\r
1664 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
1665 Speed = EFI_USB_SPEED_LOW;\r
1666 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
1667 Speed = EFI_USB_SPEED_HIGH;\r
1668 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
1669 Speed = EFI_USB_SPEED_SUPER;\r
1670 }\r
1671 //\r
1672 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
1673 //\r
a9292c13 1674 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
c3f44a77 1675 if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
6b4483cd 1676 if (Xhc->HcCParams.Data.Csz == 0) {\r
1677 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1678 } else {\r
1679 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1680 }\r
92870c98 1681 }\r
d1102dba 1682 }\r
c3f44a77 1683\r
92870c98 1684 return Status;\r
1685}\r
1686\r
1687\r
1688/**\r
1689 Calculate the device context index by endpoint address and direction.\r
1690\r
1691 @param EpAddr The target endpoint number.\r
1692 @param Direction The direction of the target endpoint.\r
1693\r
1694 @return The device context index of endpoint.\r
1695\r
1696**/\r
1697UINT8\r
1698XhcEndpointToDci (\r
1699 IN UINT8 EpAddr,\r
1700 IN UINT8 Direction\r
1701 )\r
1702{\r
1703 UINT8 Index;\r
1704\r
1705 if (EpAddr == 0) {\r
1706 return 1;\r
1707 } else {\r
ce9b5900 1708 Index = (UINT8) (2 * EpAddr);\r
92870c98 1709 if (Direction == EfiUsbDataIn) {\r
1710 Index += 1;\r
1711 }\r
1712 return Index;\r
1713 }\r
1714}\r
1715\r
92870c98 1716/**\r
1717 Find out the actual device address according to the requested device address from UsbBus.\r
1718\r
a9292c13 1719 @param Xhc The XHCI Instance.\r
1720 @param BusDevAddr The requested device address by UsbBus upper driver.\r
92870c98 1721\r
1722 @return The actual device address assigned to the device.\r
1723\r
1724**/\r
1725UINT8\r
1726EFIAPI\r
1727XhcBusDevAddrToSlotId (\r
a9292c13 1728 IN USB_XHCI_INSTANCE *Xhc,\r
1729 IN UINT8 BusDevAddr\r
92870c98 1730 )\r
1731{\r
1732 UINT8 Index;\r
1733\r
1734 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1735 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1736 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1737 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
92870c98 1738 break;\r
1739 }\r
1740 }\r
1741\r
1742 if (Index == 255) {\r
1743 return 0;\r
1744 }\r
1745\r
a9292c13 1746 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1747}\r
1748\r
1749/**\r
1750 Find out the slot id according to the device's route string.\r
1751\r
a9292c13 1752 @param Xhc The XHCI Instance.\r
1753 @param RouteString The route string described the device location.\r
92870c98 1754\r
1755 @return The slot id used by the device.\r
1756\r
1757**/\r
1758UINT8\r
1759EFIAPI\r
1760XhcRouteStringToSlotId (\r
a9292c13 1761 IN USB_XHCI_INSTANCE *Xhc,\r
1762 IN USB_DEV_ROUTE RouteString\r
92870c98 1763 )\r
1764{\r
1765 UINT8 Index;\r
1766\r
1767 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1768 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1769 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1770 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
92870c98 1771 break;\r
1772 }\r
1773 }\r
1774\r
1775 if (Index == 255) {\r
1776 return 0;\r
1777 }\r
1778\r
a9292c13 1779 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1780}\r
1781\r
1782/**\r
1783 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
1784\r
a9292c13 1785 @param Xhc The XHCI Instance.\r
92870c98 1786 @param EvtRing The event ring to sync.\r
1787\r
1788 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
1789\r
1790**/\r
1791EFI_STATUS\r
1792EFIAPI\r
1793XhcSyncEventRing (\r
a9292c13 1794 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1795 IN EVENT_RING *EvtRing\r
1796 )\r
1797{\r
1798 UINTN Index;\r
a9292c13 1799 TRB_TEMPLATE *EvtTrb1;\r
92870c98 1800\r
1801 ASSERT (EvtRing != NULL);\r
1802\r
1803 //\r
1804 // Calculate the EventRingEnqueue and EventRingCCS.\r
1805 // Note: only support single Segment\r
1806 //\r
a50f7c4c 1807 EvtTrb1 = EvtRing->EventRingDequeue;\r
92870c98 1808\r
1809 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
a50f7c4c 1810 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {\r
92870c98 1811 break;\r
1812 }\r
a50f7c4c 1813\r
92870c98 1814 EvtTrb1++;\r
a50f7c4c 1815\r
1816 if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
1817 EvtTrb1 = EvtRing->EventRingSeg0;\r
1818 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
1819 }\r
92870c98 1820 }\r
1821\r
1822 if (Index < EvtRing->TrbNumber) {\r
1823 EvtRing->EventRingEnqueue = EvtTrb1;\r
92870c98 1824 } else {\r
a50f7c4c 1825 ASSERT (FALSE);\r
92870c98 1826 }\r
1827\r
1828 return EFI_SUCCESS;\r
1829}\r
1830\r
1831/**\r
1832 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
1833\r
a9292c13 1834 @param Xhc The XHCI Instance.\r
92870c98 1835 @param TrsRing The transfer ring to sync.\r
1836\r
1837 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
1838\r
1839**/\r
1840EFI_STATUS\r
1841EFIAPI\r
1842XhcSyncTrsRing (\r
a9292c13 1843 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1844 IN TRANSFER_RING *TrsRing\r
1845 )\r
1846{\r
1847 UINTN Index;\r
a9292c13 1848 TRB_TEMPLATE *TrsTrb;\r
92870c98 1849\r
1850 ASSERT (TrsRing != NULL);\r
1851 //\r
1852 // Calculate the latest RingEnqueue and RingPCS\r
1853 //\r
1854 TrsTrb = TrsRing->RingEnqueue;\r
1855 ASSERT (TrsTrb != NULL);\r
1856\r
1857 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
1858 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
1859 break;\r
1860 }\r
1861 TrsTrb++;\r
1862 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
a9292c13 1863 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);\r
92870c98 1864 //\r
1865 // set cycle bit in Link TRB as normal\r
1866 //\r
a9292c13 1867 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
92870c98 1868 //\r
1869 // Toggle PCS maintained by software\r
1870 //\r
1871 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
1847ed0b 1872 TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address\r
92870c98 1873 }\r
1874 }\r
1875\r
1876 ASSERT (Index != TrsRing->TrbNumber);\r
1877\r
1878 if (TrsTrb != TrsRing->RingEnqueue) {\r
1879 TrsRing->RingEnqueue = TrsTrb;\r
1880 }\r
1881\r
1882 //\r
1883 // Clear the Trb context for enqueue, but reserve the PCS bit\r
1884 //\r
a9292c13 1885 TrsTrb->Parameter1 = 0;\r
1886 TrsTrb->Parameter2 = 0;\r
1887 TrsTrb->Status = 0;\r
1888 TrsTrb->RsvdZ1 = 0;\r
1889 TrsTrb->Type = 0;\r
1890 TrsTrb->Control = 0;\r
92870c98 1891\r
1892 return EFI_SUCCESS;\r
1893}\r
1894\r
1895/**\r
1896 Check if there is a new generated event.\r
1897\r
a9292c13 1898 @param Xhc The XHCI Instance.\r
92870c98 1899 @param EvtRing The event ring to check.\r
1900 @param NewEvtTrb The new event TRB found.\r
1901\r
1902 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
1903 @retval EFI_NOT_READY The event ring has no new event.\r
1904\r
1905**/\r
1906EFI_STATUS\r
1907EFIAPI\r
1908XhcCheckNewEvent (\r
a9292c13 1909 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1910 IN EVENT_RING *EvtRing,\r
a9292c13 1911 OUT TRB_TEMPLATE **NewEvtTrb\r
92870c98 1912 )\r
1913{\r
92870c98 1914 ASSERT (EvtRing != NULL);\r
1915\r
92870c98 1916 *NewEvtTrb = EvtRing->EventRingDequeue;\r
1917\r
1918 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
1919 return EFI_NOT_READY;\r
1920 }\r
1921\r
92870c98 1922 EvtRing->EventRingDequeue++;\r
1923 //\r
1924 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
1925 //\r
a50f7c4c 1926 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
92870c98 1927 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
1928 }\r
1929\r
b6cb9c39 1930 return EFI_SUCCESS;\r
92870c98 1931}\r
1932\r
1933/**\r
1934 Ring the door bell to notify XHCI there is a transaction to be executed.\r
1935\r
a9292c13 1936 @param Xhc The XHCI Instance.\r
92870c98 1937 @param SlotId The slot id of the target device.\r
1938 @param Dci The device context index of the target slot or endpoint.\r
1939\r
1940 @retval EFI_SUCCESS Successfully ring the door bell.\r
1941\r
1942**/\r
1943EFI_STATUS\r
1944EFIAPI\r
1945XhcRingDoorBell (\r
a9292c13 1946 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1947 IN UINT8 SlotId,\r
1948 IN UINT8 Dci\r
1949 )\r
1950{\r
1951 if (SlotId == 0) {\r
1952 XhcWriteDoorBellReg (Xhc, 0, 0);\r
1953 } else {\r
1954 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
1955 }\r
1956\r
1957 return EFI_SUCCESS;\r
1958}\r
1959\r
1960/**\r
1961 Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
1962\r
a9292c13 1963 @param Xhc The XHCI Instance.\r
92870c98 1964 @param Urb The URB to be rung.\r
1965\r
1966 @retval EFI_SUCCESS Successfully ring the door bell.\r
1967\r
1968**/\r
1969EFI_STATUS\r
1970RingIntTransferDoorBell (\r
a9292c13 1971 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1972 IN URB *Urb\r
1973 )\r
1974{\r
1975 UINT8 SlotId;\r
1976 UINT8 Dci;\r
1977\r
6b4483cd 1978 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1979 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
92870c98 1980 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1981 return EFI_SUCCESS;\r
1982}\r
1983\r
1984/**\r
1985 Assign and initialize the device slot for a new device.\r
1986\r
a9292c13 1987 @param Xhc The XHCI Instance.\r
92870c98 1988 @param ParentRouteChart The route string pointed to the parent device.\r
1989 @param ParentPort The port at which the device is located.\r
1990 @param RouteChart The route string pointed to the device.\r
1991 @param DeviceSpeed The device speed.\r
1992\r
1993 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
1994\r
1995**/\r
1996EFI_STATUS\r
1997EFIAPI\r
1998XhcInitializeDeviceSlot (\r
a9292c13 1999 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2000 IN USB_DEV_ROUTE ParentRouteChart,\r
2001 IN UINT16 ParentPort,\r
2002 IN USB_DEV_ROUTE RouteChart,\r
2003 IN UINT8 DeviceSpeed\r
2004 )\r
2005{\r
a9292c13 2006 EFI_STATUS Status;\r
2007 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2008 INPUT_CONTEXT *InputContext;\r
2009 DEVICE_CONTEXT *OutputContext;\r
2010 TRANSFER_RING *EndpointTransferRing;\r
2011 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2012 UINT8 DeviceAddress;\r
2013 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2014 UINT8 SlotId;\r
2015 UINT8 ParentSlotId;\r
2016 DEVICE_CONTEXT *ParentDeviceContext;\r
1847ed0b 2017 EFI_PHYSICAL_ADDRESS PhyAddr;\r
a9292c13 2018\r
2019 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
92870c98 2020 CmdTrb.CycleBit = 1;\r
2021 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
2022\r
2023 Status = XhcCmdTransfer (\r
2024 Xhc,\r
a9292c13 2025 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
92870c98 2026 XHC_GENERIC_TIMEOUT,\r
a9292c13 2027 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2028 );\r
260fbf53
EL
2029 if (EFI_ERROR (Status)) {\r
2030 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
2031 return Status;\r
2032 }\r
92870c98 2033 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
2034 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
2035 SlotId = (UINT8)EvtTrb->SlotId;\r
2036 ASSERT (SlotId != 0);\r
2037\r
a9292c13 2038 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2039 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2040 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2041 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2042 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
92870c98 2043\r
2044 //\r
2045 // 4.3.3 Device Slot Initialization\r
2046 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
2047 //\r
1847ed0b 2048 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));\r
92870c98 2049 ASSERT (InputContext != NULL);\r
2050 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
a9292c13 2051 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
92870c98 2052\r
a9292c13 2053 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
92870c98 2054\r
2055 //\r
2056 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2057 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2058 // Context are affected by the command.\r
2059 //\r
2060 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
2061\r
2062 //\r
2063 // 3) Initialize the Input Slot Context data structure\r
2064 //\r
a9292c13 2065 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
92870c98 2066 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2067 InputContext->Slot.ContextEntries = 1;\r
a9292c13 2068 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
92870c98 2069\r
a9292c13 2070 if (RouteChart.Route.RouteString) {\r
92870c98 2071 //\r
2072 // The device is behind of hub device.\r
2073 //\r
a9292c13 2074 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
92870c98 2075 ASSERT (ParentSlotId != 0);\r
2076 //\r
2077 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2078 //\r
a9292c13 2079 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
92870c98 2080 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2081 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
2082 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2083 //\r
2084 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2085 // environment from Full/Low speed signaling environment for a device\r
2086 //\r
2087 InputContext->Slot.TTPortNum = ParentPort;\r
2088 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2089 }\r
2090 } else {\r
2091 //\r
2092 // Inherit the TT parameters from parent device.\r
2093 //\r
2094 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2095 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2096 //\r
2097 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2098 //\r
2099 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2100 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2101 }\r
2102 }\r
2103 }\r
2104\r
2105 //\r
2106 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
2107 //\r
a9292c13 2108 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2109 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2110 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
92870c98 2111 //\r
2112 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2113 //\r
2114 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2115\r
2116 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2117 InputContext->EP[0].MaxPacketSize = 512;\r
2118 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2119 InputContext->EP[0].MaxPacketSize = 64;\r
2120 } else {\r
2121 InputContext->EP[0].MaxPacketSize = 8;\r
2122 }\r
2123 //\r
2124 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2125 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2126 //\r
2127 InputContext->EP[0].AverageTRBLength = 8;\r
2128 InputContext->EP[0].MaxBurstSize = 0;\r
2129 InputContext->EP[0].Interval = 0;\r
2130 InputContext->EP[0].MaxPStreams = 0;\r
2131 InputContext->EP[0].Mult = 0;\r
2132 InputContext->EP[0].CErr = 3;\r
2133\r
2134 //\r
2135 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2136 //\r
1847ed0b
EL
2137 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2138 Xhc->MemPool,\r
2139 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2140 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2141 );\r
2142 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2143 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2144\r
2145 //\r
2146 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2147 //\r
1847ed0b 2148 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));\r
a9292c13 2149 ASSERT (OutputContext != NULL);\r
2150 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2151 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
92870c98 2152\r
a9292c13 2153 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
92870c98 2154 //\r
2155 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2156 // a pointer to the Output Device Context data structure (6.2.1).\r
2157 //\r
1847ed0b
EL
2158 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
2159 //\r
2160 // Fill DCBAA with PCI device address\r
2161 //\r
2162 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
92870c98 2163\r
2164 //\r
2165 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2166 // Context data structure described above.\r
2167 //\r
26b85012
FT
2168 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2169 // to device.\r
2170 //\r
2171 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
92870c98 2172 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1847ed0b
EL
2173 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
2174 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2175 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2176 CmdTrbAddr.CycleBit = 1;\r
2177 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
a9292c13 2178 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2179 Status = XhcCmdTransfer (\r
2180 Xhc,\r
a9292c13 2181 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
92870c98 2182 XHC_GENERIC_TIMEOUT,\r
a9292c13 2183 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2184 );\r
260fbf53
EL
2185 if (!EFI_ERROR (Status)) {\r
2186 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;\r
2187 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2188 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2189 }\r
92870c98 2190\r
2191 return Status;\r
2192}\r
2193\r
2194/**\r
6b4483cd 2195 Assign and initialize the device slot for a new device.\r
92870c98 2196\r
6b4483cd 2197 @param Xhc The XHCI Instance.\r
2198 @param ParentRouteChart The route string pointed to the parent device.\r
2199 @param ParentPort The port at which the device is located.\r
2200 @param RouteChart The route string pointed to the device.\r
2201 @param DeviceSpeed The device speed.\r
92870c98 2202\r
6b4483cd 2203 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
92870c98 2204\r
2205**/\r
2206EFI_STATUS\r
2207EFIAPI\r
6b4483cd 2208XhcInitializeDeviceSlot64 (\r
2209 IN USB_XHCI_INSTANCE *Xhc,\r
2210 IN USB_DEV_ROUTE ParentRouteChart,\r
2211 IN UINT16 ParentPort,\r
2212 IN USB_DEV_ROUTE RouteChart,\r
2213 IN UINT8 DeviceSpeed\r
92870c98 2214 )\r
2215{\r
6b4483cd 2216 EFI_STATUS Status;\r
2217 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2218 INPUT_CONTEXT_64 *InputContext;\r
2219 DEVICE_CONTEXT_64 *OutputContext;\r
2220 TRANSFER_RING *EndpointTransferRing;\r
2221 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2222 UINT8 DeviceAddress;\r
2223 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2224 UINT8 SlotId;\r
2225 UINT8 ParentSlotId;\r
2226 DEVICE_CONTEXT_64 *ParentDeviceContext;\r
1847ed0b 2227 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 2228\r
6b4483cd 2229 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
2230 CmdTrb.CycleBit = 1;\r
2231 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
92870c98 2232\r
6b4483cd 2233 Status = XhcCmdTransfer (\r
2234 Xhc,\r
2235 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
2236 XHC_GENERIC_TIMEOUT,\r
2237 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2238 );\r
260fbf53
EL
2239 if (EFI_ERROR (Status)) {\r
2240 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
2241 return Status;\r
2242 }\r
6b4483cd 2243 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
2244 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
2245 SlotId = (UINT8)EvtTrb->SlotId;\r
2246 ASSERT (SlotId != 0);\r
92870c98 2247\r
6b4483cd 2248 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2249 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2250 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2251 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2252 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
92870c98 2253\r
2254 //\r
6b4483cd 2255 // 4.3.3 Device Slot Initialization\r
2256 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
92870c98 2257 //\r
1847ed0b 2258 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));\r
6b4483cd 2259 ASSERT (InputContext != NULL);\r
2260 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
2261 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2262\r
2263 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
92870c98 2264\r
92870c98 2265 //\r
6b4483cd 2266 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2267 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2268 // Context are affected by the command.\r
92870c98 2269 //\r
6b4483cd 2270 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
92870c98 2271\r
2272 //\r
6b4483cd 2273 // 3) Initialize the Input Slot Context data structure\r
92870c98 2274 //\r
6b4483cd 2275 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
2276 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2277 InputContext->Slot.ContextEntries = 1;\r
2278 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
92870c98 2279\r
6b4483cd 2280 if (RouteChart.Route.RouteString) {\r
2281 //\r
2282 // The device is behind of hub device.\r
2283 //\r
2284 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
2285 ASSERT (ParentSlotId != 0);\r
2286 //\r
2287 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2288 //\r
2289 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
2290 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2291 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
2292 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2293 //\r
2294 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2295 // environment from Full/Low speed signaling environment for a device\r
2296 //\r
2297 InputContext->Slot.TTPortNum = ParentPort;\r
2298 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2299 }\r
2300 } else {\r
2301 //\r
2302 // Inherit the TT parameters from parent device.\r
2303 //\r
2304 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2305 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2306 //\r
2307 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2308 //\r
2309 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2310 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2311 }\r
92870c98 2312 }\r
2313 }\r
2314\r
92870c98 2315 //\r
6b4483cd 2316 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
92870c98 2317 //\r
6b4483cd 2318 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2319 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2320 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
2321 //\r
2322 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2323 //\r
2324 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2325\r
2326 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2327 InputContext->EP[0].MaxPacketSize = 512;\r
2328 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2329 InputContext->EP[0].MaxPacketSize = 64;\r
2330 } else {\r
2331 InputContext->EP[0].MaxPacketSize = 8;\r
2332 }\r
2333 //\r
2334 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2335 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2336 //\r
2337 InputContext->EP[0].AverageTRBLength = 8;\r
2338 InputContext->EP[0].MaxBurstSize = 0;\r
2339 InputContext->EP[0].Interval = 0;\r
2340 InputContext->EP[0].MaxPStreams = 0;\r
2341 InputContext->EP[0].Mult = 0;\r
2342 InputContext->EP[0].CErr = 3;\r
2343\r
2344 //\r
2345 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2346 //\r
1847ed0b
EL
2347 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2348 Xhc->MemPool,\r
2349 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2350 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2351 );\r
2352 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2353 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2354\r
2355 //\r
2356 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2357 //\r
1847ed0b 2358 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));\r
6b4483cd 2359 ASSERT (OutputContext != NULL);\r
2360 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2361 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2362\r
2363 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
2364 //\r
2365 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2366 // a pointer to the Output Device Context data structure (6.2.1).\r
2367 //\r
1847ed0b
EL
2368 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2369 //\r
2370 // Fill DCBAA with PCI device address\r
2371 //\r
2372 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
6b4483cd 2373\r
2374 //\r
2375 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2376 // Context data structure described above.\r
2377 //\r
26b85012
FT
2378 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2379 // to device.\r
2380 //\r
2381 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
6b4483cd 2382 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1847ed0b
EL
2383 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
2384 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2385 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2386 CmdTrbAddr.CycleBit = 1;\r
2387 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
2388 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2389 Status = XhcCmdTransfer (\r
2390 Xhc,\r
2391 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
2392 XHC_GENERIC_TIMEOUT,\r
2393 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2394 );\r
260fbf53
EL
2395 if (!EFI_ERROR (Status)) {\r
2396 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;\r
2397 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2398 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2399 }\r
6b4483cd 2400 return Status;\r
2401}\r
2402\r
2403\r
2404/**\r
2405 Disable the specified device slot.\r
2406\r
2407 @param Xhc The XHCI Instance.\r
2408 @param SlotId The slot id to be disabled.\r
2409\r
2410 @retval EFI_SUCCESS Successfully disable the device slot.\r
2411\r
2412**/\r
2413EFI_STATUS\r
2414EFIAPI\r
2415XhcDisableSlotCmd (\r
2416 IN USB_XHCI_INSTANCE *Xhc,\r
2417 IN UINT8 SlotId\r
2418 )\r
2419{\r
2420 EFI_STATUS Status;\r
2421 TRB_TEMPLATE *EvtTrb;\r
2422 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2423 UINT8 Index;\r
2424 VOID *RingSeg;\r
2425\r
2426 //\r
2427 // Disable the device slots occupied by these devices on its downstream ports.\r
2428 // Entry 0 is reserved.\r
2429 //\r
2430 for (Index = 0; Index < 255; Index++) {\r
2431 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2432 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2433 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2434 continue;\r
2435 }\r
2436\r
2437 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2438\r
2439 if (EFI_ERROR (Status)) {\r
2440 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2441 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2442 }\r
2443 }\r
2444\r
2445 //\r
2446 // Construct the disable slot command\r
2447 //\r
2448 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
2449\r
2450 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2451 CmdTrbDisSlot.CycleBit = 1;\r
2452 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2453 CmdTrbDisSlot.SlotId = SlotId;\r
2454 Status = XhcCmdTransfer (\r
2455 Xhc,\r
2456 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2457 XHC_GENERIC_TIMEOUT,\r
2458 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2459 );\r
260fbf53
EL
2460 if (EFI_ERROR (Status)) {\r
2461 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2462 return Status;\r
2463 }\r
6b4483cd 2464 //\r
2465 // Free the slot's device context entry\r
2466 //\r
2467 Xhc->DCBAA[SlotId] = 0;\r
2468\r
2469 //\r
2470 // Free the slot related data structure\r
2471 //\r
2472 for (Index = 0; Index < 31; Index++) {\r
2473 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2474 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2475 if (RingSeg != NULL) {\r
1847ed0b 2476 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
6b4483cd 2477 }\r
2478 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1847ed0b 2479 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
6b4483cd 2480 }\r
2481 }\r
2482\r
2483 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2484 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2485 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2486 }\r
2487 }\r
2488\r
e1f2dfec
SZ
2489 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2490 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2491 }\r
2492\r
6b4483cd 2493 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1847ed0b 2494 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
6b4483cd 2495 }\r
2496\r
2497 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1847ed0b 2498 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
6b4483cd 2499 }\r
2500 //\r
2501 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2502 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2503 // remove urb from XHCI's asynchronous transfer list.\r
2504 //\r
2505 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2506 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2507\r
2508 return Status;\r
2509}\r
2510\r
2511/**\r
2512 Disable the specified device slot.\r
2513\r
2514 @param Xhc The XHCI Instance.\r
2515 @param SlotId The slot id to be disabled.\r
2516\r
2517 @retval EFI_SUCCESS Successfully disable the device slot.\r
2518\r
2519**/\r
2520EFI_STATUS\r
2521EFIAPI\r
2522XhcDisableSlotCmd64 (\r
2523 IN USB_XHCI_INSTANCE *Xhc,\r
2524 IN UINT8 SlotId\r
2525 )\r
2526{\r
2527 EFI_STATUS Status;\r
2528 TRB_TEMPLATE *EvtTrb;\r
2529 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2530 UINT8 Index;\r
2531 VOID *RingSeg;\r
2532\r
2533 //\r
2534 // Disable the device slots occupied by these devices on its downstream ports.\r
2535 // Entry 0 is reserved.\r
2536 //\r
2537 for (Index = 0; Index < 255; Index++) {\r
2538 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2539 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2540 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2541 continue;\r
2542 }\r
2543\r
2544 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2545\r
2546 if (EFI_ERROR (Status)) {\r
2547 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2548 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2549 }\r
2550 }\r
2551\r
2552 //\r
2553 // Construct the disable slot command\r
2554 //\r
2555 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
2556\r
2557 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2558 CmdTrbDisSlot.CycleBit = 1;\r
2559 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2560 CmdTrbDisSlot.SlotId = SlotId;\r
2561 Status = XhcCmdTransfer (\r
2562 Xhc,\r
2563 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2564 XHC_GENERIC_TIMEOUT,\r
2565 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2566 );\r
260fbf53
EL
2567 if (EFI_ERROR (Status)) {\r
2568 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2569 return Status;\r
2570 }\r
6b4483cd 2571 //\r
2572 // Free the slot's device context entry\r
2573 //\r
2574 Xhc->DCBAA[SlotId] = 0;\r
2575\r
2576 //\r
2577 // Free the slot related data structure\r
2578 //\r
2579 for (Index = 0; Index < 31; Index++) {\r
2580 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2581 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2582 if (RingSeg != NULL) {\r
1847ed0b 2583 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
6b4483cd 2584 }\r
2585 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1847ed0b 2586 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
6b4483cd 2587 }\r
2588 }\r
2589\r
2590 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2591 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2592 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2593 }\r
2594 }\r
2595\r
e1f2dfec
SZ
2596 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2597 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2598 }\r
2599\r
6b4483cd 2600 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1847ed0b 2601 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
6b4483cd 2602 }\r
2603\r
2604 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1847ed0b 2605 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
6b4483cd 2606 }\r
2607 //\r
2608 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2609 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2610 // remove urb from XHCI's asynchronous transfer list.\r
2611 //\r
2612 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2613 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2614\r
2615 return Status;\r
2616}\r
2617\r
e1f2dfec
SZ
2618/**\r
2619 Initialize endpoint context in input context.\r
2620\r
2621 @param Xhc The XHCI Instance.\r
2622 @param SlotId The slot id to be configured.\r
2623 @param DeviceSpeed The device's speed.\r
2624 @param InputContext The pointer to the input context.\r
2625 @param IfDesc The pointer to the usb device interface descriptor.\r
2626\r
2627 @return The maximum device context index of endpoint.\r
2628\r
2629**/\r
2630UINT8\r
2631EFIAPI\r
2632XhcInitializeEndpointContext (\r
2633 IN USB_XHCI_INSTANCE *Xhc,\r
2634 IN UINT8 SlotId,\r
2635 IN UINT8 DeviceSpeed,\r
2636 IN INPUT_CONTEXT *InputContext,\r
2637 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2638 )\r
2639{\r
2640 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2641 UINTN NumEp;\r
2642 UINTN EpIndex;\r
2643 UINT8 EpAddr;\r
2644 UINT8 Direction;\r
2645 UINT8 Dci;\r
2646 UINT8 MaxDci;\r
2647 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2648 UINT8 Interval;\r
2649 TRANSFER_RING *EndpointTransferRing;\r
2650\r
2651 MaxDci = 0;\r
2652\r
2653 NumEp = IfDesc->NumEndpoints;\r
2654\r
2655 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2656 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2657 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2658 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2659 }\r
2660\r
fd5d2dd2
FT
2661 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
2662 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2663 continue;\r
2664 }\r
2665\r
e1f2dfec
SZ
2666 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2667 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2668\r
2669 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2670 ASSERT (Dci < 32);\r
2671 if (Dci > MaxDci) {\r
2672 MaxDci = Dci;\r
2673 }\r
2674\r
2675 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2676 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2677\r
2678 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2679 //\r
2680 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2681 //\r
2682 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2683 } else {\r
2684 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2685 }\r
2686\r
2687 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2688 case USB_ENDPOINT_BULK:\r
2689 if (Direction == EfiUsbDataIn) {\r
2690 InputContext->EP[Dci-1].CErr = 3;\r
2691 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2692 } else {\r
2693 InputContext->EP[Dci-1].CErr = 3;\r
2694 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2695 }\r
2696\r
2697 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2698 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2699 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2700 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2701 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
2702 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created BULK ring [%p~%p)\n",\r
2703 EpDesc->EndpointAddress,\r
2704 EndpointTransferRing->RingSeg0,\r
2705 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2706 ));\r
e1f2dfec
SZ
2707 }\r
2708\r
2709 break;\r
2710 case USB_ENDPOINT_ISO:\r
2711 if (Direction == EfiUsbDataIn) {\r
2712 InputContext->EP[Dci-1].CErr = 0;\r
2713 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2714 } else {\r
2715 InputContext->EP[Dci-1].CErr = 0;\r
2716 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2717 }\r
3719c2aa
HW
2718 //\r
2719 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
2720 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
2721 //\r
2722 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
2723 Interval = EpDesc->Interval;\r
2724 ASSERT (Interval >= 1 && Interval <= 16);\r
2725 InputContext->EP[Dci-1].Interval = Interval + 2;\r
2726 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2727 Interval = EpDesc->Interval;\r
2728 ASSERT (Interval >= 1 && Interval <= 16);\r
2729 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2730 }\r
2731\r
acedecdd
EL
2732 //\r
2733 // Do not support isochronous transfer now.\r
2734 //\r
2735 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
2736 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2737 continue;\r
e1f2dfec
SZ
2738 case USB_ENDPOINT_INTERRUPT:\r
2739 if (Direction == EfiUsbDataIn) {\r
2740 InputContext->EP[Dci-1].CErr = 3;\r
2741 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2742 } else {\r
2743 InputContext->EP[Dci-1].CErr = 3;\r
2744 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2745 }\r
2746 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2747 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2748 //\r
2749 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2750 //\r
2751 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2752 Interval = EpDesc->Interval;\r
2753 //\r
2754 // Calculate through the bInterval field of Endpoint descriptor.\r
2755 //\r
2756 ASSERT (Interval != 0);\r
2757 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;\r
2758 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2759 Interval = EpDesc->Interval;\r
2760 ASSERT (Interval >= 1 && Interval <= 16);\r
2761 //\r
2762 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2763 //\r
2764 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2765 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2766 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2767 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2768 InputContext->EP[Dci-1].CErr = 3;\r
2769 }\r
2770\r
2771 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2772 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2773 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2774 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
2775 DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created INT ring [%p~%p)\n",\r
2776 EpDesc->EndpointAddress,\r
2777 EndpointTransferRing->RingSeg0,\r
2778 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2779 ));\r
e1f2dfec
SZ
2780 }\r
2781 break;\r
2782\r
2783 case USB_ENDPOINT_CONTROL:\r
acedecdd
EL
2784 //\r
2785 // Do not support control transfer now.\r
2786 //\r
2787 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
e1f2dfec 2788 default:\r
acedecdd
EL
2789 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));\r
2790 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2791 continue;\r
e1f2dfec
SZ
2792 }\r
2793\r
2794 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2795 Xhc->MemPool,\r
2796 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2797 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2798 );\r
6e1e5405
FT
2799 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
2800 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
e1f2dfec
SZ
2801 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2802 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2803\r
2804 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2805 }\r
2806\r
2807 return MaxDci;\r
2808}\r
2809\r
2810/**\r
2811 Initialize endpoint context in input context.\r
2812\r
2813 @param Xhc The XHCI Instance.\r
2814 @param SlotId The slot id to be configured.\r
2815 @param DeviceSpeed The device's speed.\r
2816 @param InputContext The pointer to the input context.\r
2817 @param IfDesc The pointer to the usb device interface descriptor.\r
2818\r
2819 @return The maximum device context index of endpoint.\r
2820\r
2821**/\r
2822UINT8\r
2823EFIAPI\r
2824XhcInitializeEndpointContext64 (\r
2825 IN USB_XHCI_INSTANCE *Xhc,\r
2826 IN UINT8 SlotId,\r
2827 IN UINT8 DeviceSpeed,\r
2828 IN INPUT_CONTEXT_64 *InputContext,\r
2829 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2830 )\r
2831{\r
2832 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2833 UINTN NumEp;\r
2834 UINTN EpIndex;\r
2835 UINT8 EpAddr;\r
2836 UINT8 Direction;\r
2837 UINT8 Dci;\r
2838 UINT8 MaxDci;\r
2839 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2840 UINT8 Interval;\r
2841 TRANSFER_RING *EndpointTransferRing;\r
2842\r
2843 MaxDci = 0;\r
2844\r
2845 NumEp = IfDesc->NumEndpoints;\r
2846\r
2847 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2848 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2849 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2850 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2851 }\r
2852\r
fd5d2dd2
FT
2853 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
2854 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2855 continue;\r
2856 }\r
2857\r
e1f2dfec
SZ
2858 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2859 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2860\r
2861 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2862 ASSERT (Dci < 32);\r
2863 if (Dci > MaxDci) {\r
2864 MaxDci = Dci;\r
2865 }\r
2866\r
2867 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2868 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2869\r
2870 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2871 //\r
2872 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2873 //\r
2874 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2875 } else {\r
2876 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2877 }\r
2878\r
2879 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2880 case USB_ENDPOINT_BULK:\r
2881 if (Direction == EfiUsbDataIn) {\r
2882 InputContext->EP[Dci-1].CErr = 3;\r
2883 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2884 } else {\r
2885 InputContext->EP[Dci-1].CErr = 3;\r
2886 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2887 }\r
2888\r
2889 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2890 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2891 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2892 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2893 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
2894 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",\r
2895 EpDesc->EndpointAddress,\r
2896 EndpointTransferRing->RingSeg0,\r
2897 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2898 ));\r
e1f2dfec
SZ
2899 }\r
2900\r
2901 break;\r
2902 case USB_ENDPOINT_ISO:\r
2903 if (Direction == EfiUsbDataIn) {\r
2904 InputContext->EP[Dci-1].CErr = 0;\r
2905 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2906 } else {\r
2907 InputContext->EP[Dci-1].CErr = 0;\r
2908 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2909 }\r
3719c2aa
HW
2910 //\r
2911 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
2912 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
2913 //\r
2914 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
2915 Interval = EpDesc->Interval;\r
2916 ASSERT (Interval >= 1 && Interval <= 16);\r
2917 InputContext->EP[Dci-1].Interval = Interval + 2;\r
2918 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2919 Interval = EpDesc->Interval;\r
2920 ASSERT (Interval >= 1 && Interval <= 16);\r
2921 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2922 }\r
2923\r
acedecdd
EL
2924 //\r
2925 // Do not support isochronous transfer now.\r
2926 //\r
2927 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
2928 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2929 continue;\r
e1f2dfec
SZ
2930 case USB_ENDPOINT_INTERRUPT:\r
2931 if (Direction == EfiUsbDataIn) {\r
2932 InputContext->EP[Dci-1].CErr = 3;\r
2933 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2934 } else {\r
2935 InputContext->EP[Dci-1].CErr = 3;\r
2936 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2937 }\r
2938 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2939 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2940 //\r
2941 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2942 //\r
2943 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2944 Interval = EpDesc->Interval;\r
2945 //\r
2946 // Calculate through the bInterval field of Endpoint descriptor.\r
2947 //\r
2948 ASSERT (Interval != 0);\r
2949 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32((UINT32)Interval) + 3;\r
2950 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2951 Interval = EpDesc->Interval;\r
2952 ASSERT (Interval >= 1 && Interval <= 16);\r
2953 //\r
2954 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2955 //\r
2956 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2957 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2958 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2959 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2960 InputContext->EP[Dci-1].CErr = 3;\r
2961 }\r
2962\r
2963 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2964 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2965 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2966 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
396ae94d
RN
2967 DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created INT ring [%p~%p)\n",\r
2968 EpDesc->EndpointAddress,\r
2969 EndpointTransferRing->RingSeg0,\r
2970 (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2971 ));\r
e1f2dfec
SZ
2972 }\r
2973 break;\r
2974\r
2975 case USB_ENDPOINT_CONTROL:\r
acedecdd
EL
2976 //\r
2977 // Do not support control transfer now.\r
2978 //\r
2979 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
e1f2dfec 2980 default:\r
acedecdd
EL
2981 DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));\r
2982 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2983 continue;\r
e1f2dfec
SZ
2984 }\r
2985\r
2986 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2987 Xhc->MemPool,\r
2988 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2989 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2990 );\r
6e1e5405
FT
2991 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
2992 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
e1f2dfec
SZ
2993 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2994 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2995\r
2996 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2997 }\r
2998\r
2999 return MaxDci;\r
3000}\r
6b4483cd 3001\r
3002/**\r
3003 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
3004\r
3005 @param Xhc The XHCI Instance.\r
3006 @param SlotId The slot id to be configured.\r
3007 @param DeviceSpeed The device's speed.\r
3008 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3009\r
3010 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
3011\r
3012**/\r
3013EFI_STATUS\r
3014EFIAPI\r
3015XhcSetConfigCmd (\r
3016 IN USB_XHCI_INSTANCE *Xhc,\r
3017 IN UINT8 SlotId,\r
3018 IN UINT8 DeviceSpeed,\r
3019 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
3020 )\r
3021{\r
3022 EFI_STATUS Status;\r
6b4483cd 3023 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
6b4483cd 3024 UINT8 Index;\r
6b4483cd 3025 UINT8 Dci;\r
3026 UINT8 MaxDci;\r
1847ed0b 3027 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 3028\r
6b4483cd 3029 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3030 INPUT_CONTEXT *InputContext;\r
3031 DEVICE_CONTEXT *OutputContext;\r
3032 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3033 //\r
3034 // 4.6.6 Configure Endpoint\r
3035 //\r
3036 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3037 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3038 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3039 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
3040\r
3041 ASSERT (ConfigDesc != NULL);\r
3042\r
3043 MaxDci = 0;\r
3044\r
3045 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3046 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
e1f2dfec 3047 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
6b4483cd 3048 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3049 }\r
3050\r
fd5d2dd2
FT
3051 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
3052 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3053 continue;\r
3054 }\r
3055\r
e1f2dfec
SZ
3056 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
3057 if (Dci > MaxDci) {\r
3058 MaxDci = Dci;\r
6b4483cd 3059 }\r
e1f2dfec 3060\r
6b4483cd 3061 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3062 }\r
3063\r
3064 InputContext->InputControlContext.Dword2 |= BIT0;\r
3065 InputContext->Slot.ContextEntries = MaxDci;\r
3066 //\r
3067 // configure endpoint\r
3068 //\r
3069 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3070 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3071 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3072 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 3073 CmdTrbCfgEP.CycleBit = 1;\r
3074 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3075 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3076 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
3077 Status = XhcCmdTransfer (\r
3078 Xhc,\r
3079 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3080 XHC_GENERIC_TIMEOUT,\r
3081 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3082 );\r
260fbf53
EL
3083 if (EFI_ERROR (Status)) {\r
3084 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
e1f2dfec
SZ
3085 } else {\r
3086 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
260fbf53 3087 }\r
e1f2dfec 3088\r
92870c98 3089 return Status;\r
3090}\r
3091\r
3092/**\r
3093 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
3094\r
a9292c13 3095 @param Xhc The XHCI Instance.\r
92870c98 3096 @param SlotId The slot id to be configured.\r
3097 @param DeviceSpeed The device's speed.\r
3098 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3099\r
3100 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
3101\r
3102**/\r
3103EFI_STATUS\r
3104EFIAPI\r
6b4483cd 3105XhcSetConfigCmd64 (\r
a9292c13 3106 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 3107 IN UINT8 SlotId,\r
a9292c13 3108 IN UINT8 DeviceSpeed,\r
92870c98 3109 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
3110 )\r
3111{\r
a9292c13 3112 EFI_STATUS Status;\r
a9292c13 3113 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
a9292c13 3114 UINT8 Index;\r
a9292c13 3115 UINT8 Dci;\r
3116 UINT8 MaxDci;\r
1847ed0b 3117 EFI_PHYSICAL_ADDRESS PhyAddr;\r
a9292c13 3118\r
a9292c13 3119 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
6b4483cd 3120 INPUT_CONTEXT_64 *InputContext;\r
3121 DEVICE_CONTEXT_64 *OutputContext;\r
a9292c13 3122 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
92870c98 3123 //\r
3124 // 4.6.6 Configure Endpoint\r
3125 //\r
a9292c13 3126 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3127 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
6b4483cd 3128 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3129 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
92870c98 3130\r
3131 ASSERT (ConfigDesc != NULL);\r
3132\r
3133 MaxDci = 0;\r
3134\r
3135 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3136 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
e1f2dfec 3137 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
92870c98 3138 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3139 }\r
3140\r
fd5d2dd2
FT
3141 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
3142 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3143 continue;\r
3144 }\r
3145\r
e1f2dfec
SZ
3146 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
3147 if (Dci > MaxDci) {\r
3148 MaxDci = Dci;\r
92870c98 3149 }\r
d1102dba 3150\r
92870c98 3151 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3152 }\r
3153\r
3154 InputContext->InputControlContext.Dword2 |= BIT0;\r
3155 InputContext->Slot.ContextEntries = MaxDci;\r
3156 //\r
3157 // configure endpoint\r
3158 //\r
3159 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3160 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3161 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3162 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 3163 CmdTrbCfgEP.CycleBit = 1;\r
3164 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 3165 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 3166 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
3167 Status = XhcCmdTransfer (\r
3168 Xhc,\r
a9292c13 3169 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 3170 XHC_GENERIC_TIMEOUT,\r
a9292c13 3171 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 3172 );\r
260fbf53
EL
3173 if (EFI_ERROR (Status)) {\r
3174 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
e1f2dfec
SZ
3175 } else {\r
3176 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
3177 }\r
3178\r
3179 return Status;\r
3180}\r
3181\r
3182/**\r
3183 Stop endpoint through XHCI's Stop_Endpoint cmd.\r
3184\r
3185 @param Xhc The XHCI Instance.\r
3186 @param SlotId The slot id to be configured.\r
3187 @param Dci The device context index of endpoint.\r
49be9c3c 3188 @param PendingUrb The pending URB to check completion status when stopping the end point.\r
e1f2dfec
SZ
3189\r
3190 @retval EFI_SUCCESS Stop endpoint successfully.\r
3191 @retval Others Failed to stop endpoint.\r
3192\r
3193**/\r
3194EFI_STATUS\r
3195EFIAPI\r
3196XhcStopEndpoint (\r
3197 IN USB_XHCI_INSTANCE *Xhc,\r
3198 IN UINT8 SlotId,\r
49be9c3c
RN
3199 IN UINT8 Dci,\r
3200 IN URB *PendingUrb OPTIONAL\r
e1f2dfec
SZ
3201 )\r
3202{\r
3203 EFI_STATUS Status;\r
3204 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3205 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;\r
3206\r
3207 DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
3208\r
49be9c3c
RN
3209 //\r
3210 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks\r
3211 // the PendingUrb completion status, because it's possible that the PendingUrb is\r
3212 // finished just before stopping the end point, but after the looping check.\r
3213 //\r
3214 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult\r
3215 // through function parameter, but That will cause every consumer of XhcCmdTransfer,\r
3216 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.\r
3217 // But actually only XhcCheckUrbResult is aware of the PendingUrb.\r
3218 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.\r
3219 //\r
3220 ASSERT (Xhc->PendingUrb == NULL);\r
3221 Xhc->PendingUrb = PendingUrb;\r
3222 //\r
3223 // Reset the URB result from Timeout to NoError.\r
3224 // The USB result will be:\r
3225 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or\r
3226 // remain NoError when Success/ShortPacket Transfer Event is received.\r
3227 //\r
3228 if (PendingUrb != NULL) {\r
3229 PendingUrb->Result = EFI_USB_NOERROR;\r
3230 }\r
3231\r
e1f2dfec
SZ
3232 //\r
3233 // Send stop endpoint command to transit Endpoint from running to stop state\r
3234 //\r
3235 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));\r
3236 CmdTrbStopED.CycleBit = 1;\r
3237 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;\r
3238 CmdTrbStopED.EDID = Dci;\r
3239 CmdTrbStopED.SlotId = SlotId;\r
3240 Status = XhcCmdTransfer (\r
3241 Xhc,\r
3242 (TRB_TEMPLATE *) (UINTN) &CmdTrbStopED,\r
3243 XHC_GENERIC_TIMEOUT,\r
3244 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3245 );\r
3246 if (EFI_ERROR(Status)) {\r
3247 DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
3248 }\r
3249\r
49be9c3c
RN
3250 Xhc->PendingUrb = NULL;\r
3251\r
e1f2dfec
SZ
3252 return Status;\r
3253}\r
3254\r
12e6c738
FT
3255/**\r
3256 Reset endpoint through XHCI's Reset_Endpoint cmd.\r
3257\r
3258 @param Xhc The XHCI Instance.\r
3259 @param SlotId The slot id to be configured.\r
3260 @param Dci The device context index of endpoint.\r
3261\r
3262 @retval EFI_SUCCESS Reset endpoint successfully.\r
3263 @retval Others Failed to reset endpoint.\r
3264\r
3265**/\r
3266EFI_STATUS\r
3267EFIAPI\r
3268XhcResetEndpoint (\r
3269 IN USB_XHCI_INSTANCE *Xhc,\r
3270 IN UINT8 SlotId,\r
3271 IN UINT8 Dci\r
3272 )\r
3273{\r
3274 EFI_STATUS Status;\r
3275 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3276 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
3277\r
3278 DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
3279\r
3280 //\r
3281 // Send stop endpoint command to transit Endpoint from running to stop state\r
3282 //\r
3283 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
3284 CmdTrbResetED.CycleBit = 1;\r
3285 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
3286 CmdTrbResetED.EDID = Dci;\r
3287 CmdTrbResetED.SlotId = SlotId;\r
3288 Status = XhcCmdTransfer (\r
3289 Xhc,\r
3290 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
3291 XHC_GENERIC_TIMEOUT,\r
3292 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3293 );\r
3294 if (EFI_ERROR(Status)) {\r
3295 DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
3296 }\r
3297\r
3298 return Status;\r
3299}\r
3300\r
3301/**\r
3302 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
3303\r
3304 @param Xhc The XHCI Instance.\r
3305 @param SlotId The slot id to be configured.\r
3306 @param Dci The device context index of endpoint.\r
3307 @param Urb The dequeue pointer of the transfer ring specified\r
3308 by the urb to be updated.\r
3309\r
3310 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.\r
3311 @retval Others Failed to set transfer ring dequeue pointer.\r
3312\r
3313**/\r
3314EFI_STATUS\r
3315EFIAPI\r
3316XhcSetTrDequeuePointer (\r
3317 IN USB_XHCI_INSTANCE *Xhc,\r
3318 IN UINT8 SlotId,\r
3319 IN UINT8 Dci,\r
3320 IN URB *Urb\r
3321 )\r
3322{\r
3323 EFI_STATUS Status;\r
3324 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3325 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
3326 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3327\r
3328 DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
3329\r
3330 //\r
3331 // Send stop endpoint command to transit Endpoint from running to stop state\r
3332 //\r
3333 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
3334 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
3335 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
3336 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3337 CmdSetTRDeq.CycleBit = 1;\r
3338 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
3339 CmdSetTRDeq.Endpoint = Dci;\r
3340 CmdSetTRDeq.SlotId = SlotId;\r
3341 Status = XhcCmdTransfer (\r
3342 Xhc,\r
3343 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
3344 XHC_GENERIC_TIMEOUT,\r
3345 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3346 );\r
3347 if (EFI_ERROR(Status)) {\r
3348 DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
3349 }\r
3350\r
3351 return Status;\r
3352}\r
3353\r
e1f2dfec
SZ
3354/**\r
3355 Set interface through XHCI's Configure_Endpoint cmd.\r
3356\r
3357 @param Xhc The XHCI Instance.\r
3358 @param SlotId The slot id to be configured.\r
3359 @param DeviceSpeed The device's speed.\r
3360 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3361 @param Request USB device request to send.\r
3362\r
3363 @retval EFI_SUCCESS Successfully set interface.\r
3364\r
3365**/\r
3366EFI_STATUS\r
3367EFIAPI\r
3368XhcSetInterface (\r
3369 IN USB_XHCI_INSTANCE *Xhc,\r
3370 IN UINT8 SlotId,\r
3371 IN UINT8 DeviceSpeed,\r
3372 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3373 IN EFI_USB_DEVICE_REQUEST *Request\r
3374 )\r
3375{\r
3376 EFI_STATUS Status;\r
3377 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3378 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3379 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3380 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3381 UINTN NumEp;\r
3382 UINTN EpIndex;\r
3383 UINT8 EpAddr;\r
3384 UINT8 Direction;\r
3385 UINT8 Dci;\r
3386 UINT8 MaxDci;\r
3387 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3388 VOID *RingSeg;\r
3389\r
3390 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3391 INPUT_CONTEXT *InputContext;\r
3392 DEVICE_CONTEXT *OutputContext;\r
3393 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3394\r
3395 Status = EFI_SUCCESS;\r
3396\r
3397 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3398 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3399 //\r
3400 // XHCI 4.6.6 Configure Endpoint\r
3401 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3402 // Context and Add Context flags as follows:\r
3403 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3404 // Context and Add Context flags to '0'.\r
3405 //\r
3406 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3407 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3408 //\r
3409 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3410 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
3411\r
3412 ASSERT (ConfigDesc != NULL);\r
3413\r
3414 MaxDci = 0;\r
3415\r
3416 IfDescActive = NULL;\r
3417 IfDescSet = NULL;\r
3418\r
3419 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3420 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
fd5d2dd2 3421 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
e1f2dfec
SZ
3422 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
3423 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3424 //\r
3425 // Find out the active interface descriptor.\r
3426 //\r
3427 IfDescActive = IfDesc;\r
3428 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {\r
3429 //\r
3430 // Find out the interface descriptor to set.\r
3431 //\r
3432 IfDescSet = IfDesc;\r
3433 }\r
3434 }\r
3435 }\r
3436 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3437 }\r
3438\r
3439 //\r
3440 // XHCI 4.6.6 Configure Endpoint\r
3441 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3442 // Context and Add Context flags as follows:\r
3443 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3444 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3445 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3446 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3447 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3448 // and Add Context flags shall be set to '1'.\r
3449 //\r
3450 // Below codes are to cover 2), 3) and 4).\r
3451 //\r
3452\r
3453 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3454 NumEp = IfDescActive->NumEndpoints;\r
3455 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);\r
3456 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3457 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3458 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3459 }\r
3460\r
fd5d2dd2
FT
3461 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3462 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3463 continue;\r
3464 }\r
3465\r
e1f2dfec
SZ
3466 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
3467 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3468\r
3469 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3470 ASSERT (Dci < 32);\r
3471 if (Dci > MaxDci) {\r
3472 MaxDci = Dci;\r
3473 }\r
3474 //\r
3475 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3476 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3477 //\r
49be9c3c 3478 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
e1f2dfec
SZ
3479 if (EFI_ERROR (Status)) {\r
3480 return Status;\r
3481 }\r
3482 //\r
3483 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3484 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3485 //\r
3486 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3487 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3488 if (RingSeg != NULL) {\r
3489 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3490 }\r
3491 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3492 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3493 }\r
3494\r
3495 //\r
3496 // Set the Drop Context flag to '1'.\r
3497 //\r
3498 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3499\r
3500 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3501 }\r
3502\r
3503 //\r
3504 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3505 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3506 // Interface setting, to '0'.\r
3507 //\r
3508 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3509 //\r
3510\r
3511 //\r
3512 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3513 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3514 // a. Allocate a Transfer Ring.\r
3515 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3516 // c. Initialize the Endpoint Context data structure.\r
3517 //\r
3518 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3519 if (Dci > MaxDci) {\r
3520 MaxDci = Dci;\r
3521 }\r
3522\r
3523 InputContext->InputControlContext.Dword2 |= BIT0;\r
3524 InputContext->Slot.ContextEntries = MaxDci;\r
3525 //\r
3526 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3527 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3528 //\r
3529 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3530 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3531 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3532 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3533 CmdTrbCfgEP.CycleBit = 1;\r
3534 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3535 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3536 DEBUG ((EFI_D_INFO, "SetInterface: Configure Endpoint\n"));\r
3537 Status = XhcCmdTransfer (\r
3538 Xhc,\r
3539 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3540 XHC_GENERIC_TIMEOUT,\r
3541 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3542 );\r
3543 if (EFI_ERROR (Status)) {\r
3544 DEBUG ((EFI_D_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));\r
3545 } else {\r
3546 //\r
3547 // Update the active AlternateSetting.\r
3548 //\r
3549 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;\r
3550 }\r
260fbf53 3551 }\r
92870c98 3552\r
3553 return Status;\r
3554}\r
3555\r
e1f2dfec
SZ
3556/**\r
3557 Set interface through XHCI's Configure_Endpoint cmd.\r
3558\r
3559 @param Xhc The XHCI Instance.\r
3560 @param SlotId The slot id to be configured.\r
3561 @param DeviceSpeed The device's speed.\r
3562 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3563 @param Request USB device request to send.\r
3564\r
3565 @retval EFI_SUCCESS Successfully set interface.\r
3566\r
3567**/\r
3568EFI_STATUS\r
3569EFIAPI\r
3570XhcSetInterface64 (\r
3571 IN USB_XHCI_INSTANCE *Xhc,\r
3572 IN UINT8 SlotId,\r
3573 IN UINT8 DeviceSpeed,\r
3574 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3575 IN EFI_USB_DEVICE_REQUEST *Request\r
3576 )\r
3577{\r
3578 EFI_STATUS Status;\r
3579 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3580 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3581 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3582 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3583 UINTN NumEp;\r
3584 UINTN EpIndex;\r
3585 UINT8 EpAddr;\r
3586 UINT8 Direction;\r
3587 UINT8 Dci;\r
3588 UINT8 MaxDci;\r
3589 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3590 VOID *RingSeg;\r
3591\r
3592 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3593 INPUT_CONTEXT_64 *InputContext;\r
3594 DEVICE_CONTEXT_64 *OutputContext;\r
3595 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3596\r
3597 Status = EFI_SUCCESS;\r
3598\r
3599 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3600 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3601 //\r
3602 // XHCI 4.6.6 Configure Endpoint\r
3603 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3604 // Context and Add Context flags as follows:\r
3605 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3606 // Context and Add Context flags to '0'.\r
3607 //\r
3608 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3609 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3610 //\r
3611 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3612 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
3613\r
3614 ASSERT (ConfigDesc != NULL);\r
3615\r
3616 MaxDci = 0;\r
3617\r
3618 IfDescActive = NULL;\r
3619 IfDescSet = NULL;\r
3620\r
3621 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3622 while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
fd5d2dd2 3623 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
e1f2dfec
SZ
3624 if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
3625 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3626 //\r
3627 // Find out the active interface descriptor.\r
3628 //\r
3629 IfDescActive = IfDesc;\r
3630 } else if (IfDesc->AlternateSetting == (UINT8) Request->Value) {\r
3631 //\r
3632 // Find out the interface descriptor to set.\r
3633 //\r
3634 IfDescSet = IfDesc;\r
3635 }\r
3636 }\r
3637 }\r
3638 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3639 }\r
3640\r
3641 //\r
3642 // XHCI 4.6.6 Configure Endpoint\r
3643 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3644 // Context and Add Context flags as follows:\r
3645 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3646 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3647 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3648 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3649 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3650 // and Add Context flags shall be set to '1'.\r
3651 //\r
3652 // Below codes are to cover 2), 3) and 4).\r
3653 //\r
3654\r
3655 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3656 NumEp = IfDescActive->NumEndpoints;\r
3657 EpDesc = (USB_ENDPOINT_DESCRIPTOR *) (IfDescActive + 1);\r
3658 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3659 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3660 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3661 }\r
3662\r
fd5d2dd2
FT
3663 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3664 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3665 continue;\r
3666 }\r
3667\r
e1f2dfec
SZ
3668 EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
3669 Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3670\r
3671 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3672 ASSERT (Dci < 32);\r
3673 if (Dci > MaxDci) {\r
3674 MaxDci = Dci;\r
3675 }\r
3676 //\r
3677 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3678 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3679 //\r
49be9c3c 3680 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
e1f2dfec
SZ
3681 if (EFI_ERROR (Status)) {\r
3682 return Status;\r
3683 }\r
3684 //\r
3685 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3686 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3687 //\r
3688 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3689 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3690 if (RingSeg != NULL) {\r
3691 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3692 }\r
3693 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3694 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3695 }\r
3696\r
3697 //\r
3698 // Set the Drop Context flag to '1'.\r
3699 //\r
3700 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3701\r
3702 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3703 }\r
3704\r
3705 //\r
3706 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3707 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3708 // Interface setting, to '0'.\r
3709 //\r
3710 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3711 //\r
3712\r
3713 //\r
3714 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3715 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3716 // a. Allocate a Transfer Ring.\r
3717 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3718 // c. Initialize the Endpoint Context data structure.\r
3719 //\r
3720 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3721 if (Dci > MaxDci) {\r
3722 MaxDci = Dci;\r
3723 }\r
3724\r
3725 InputContext->InputControlContext.Dword2 |= BIT0;\r
3726 InputContext->Slot.ContextEntries = MaxDci;\r
3727 //\r
3728 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3729 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3730 //\r
3731 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3732 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3733 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3734 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3735 CmdTrbCfgEP.CycleBit = 1;\r
3736 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3737 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3738 DEBUG ((EFI_D_INFO, "SetInterface64: Configure Endpoint\n"));\r
3739 Status = XhcCmdTransfer (\r
3740 Xhc,\r
3741 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3742 XHC_GENERIC_TIMEOUT,\r
3743 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3744 );\r
3745 if (EFI_ERROR (Status)) {\r
3746 DEBUG ((EFI_D_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));\r
3747 } else {\r
3748 //\r
3749 // Update the active AlternateSetting.\r
3750 //\r
3751 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] = (UINT8) Request->Value;\r
3752 }\r
3753 }\r
3754\r
3755 return Status;\r
3756}\r
6b4483cd 3757\r
92870c98 3758/**\r
3759 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
3760\r
a9292c13 3761 @param Xhc The XHCI Instance.\r
92870c98 3762 @param SlotId The slot id to be evaluated.\r
3763 @param MaxPacketSize The max packet size supported by the device control transfer.\r
3764\r
3765 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
3766\r
3767**/\r
3768EFI_STATUS\r
3769EFIAPI\r
3770XhcEvaluateContext (\r
a9292c13 3771 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 3772 IN UINT8 SlotId,\r
3773 IN UINT32 MaxPacketSize\r
3774 )\r
3775{\r
a9292c13 3776 EFI_STATUS Status;\r
3777 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
3778 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3779 INPUT_CONTEXT *InputContext;\r
1847ed0b 3780 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 3781\r
a9292c13 3782 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
92870c98 3783\r
3784 //\r
3785 // 4.6.7 Evaluate Context\r
3786 //\r
a9292c13 3787 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
92870c98 3788 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3789\r
3790 InputContext->InputControlContext.Dword2 |= BIT1;\r
3791 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
3792\r
3793 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1847ed0b
EL
3794 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3795 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3796 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 3797 CmdTrbEvalu.CycleBit = 1;\r
3798 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
a9292c13 3799 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 3800 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
3801 Status = XhcCmdTransfer (\r
3802 Xhc,\r
a9292c13 3803 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
92870c98 3804 XHC_GENERIC_TIMEOUT,\r
a9292c13 3805 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 3806 );\r
260fbf53
EL
3807 if (EFI_ERROR (Status)) {\r
3808 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
3809 }\r
92870c98 3810 return Status;\r
3811}\r
3812\r
6b4483cd 3813/**\r
3814 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
3815\r
3816 @param Xhc The XHCI Instance.\r
3817 @param SlotId The slot id to be evaluated.\r
3818 @param MaxPacketSize The max packet size supported by the device control transfer.\r
3819\r
3820 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
3821\r
3822**/\r
3823EFI_STATUS\r
3824EFIAPI\r
3825XhcEvaluateContext64 (\r
3826 IN USB_XHCI_INSTANCE *Xhc,\r
3827 IN UINT8 SlotId,\r
3828 IN UINT32 MaxPacketSize\r
3829 )\r
3830{\r
3831 EFI_STATUS Status;\r
3832 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
3833 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3834 INPUT_CONTEXT_64 *InputContext;\r
1847ed0b 3835 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 3836\r
3837 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3838\r
3839 //\r
3840 // 4.6.7 Evaluate Context\r
3841 //\r
3842 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3843 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3844\r
3845 InputContext->InputControlContext.Dword2 |= BIT1;\r
3846 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
3847\r
3848 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1847ed0b
EL
3849 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3850 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3851 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 3852 CmdTrbEvalu.CycleBit = 1;\r
3853 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
3854 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3855 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
3856 Status = XhcCmdTransfer (\r
3857 Xhc,\r
3858 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
3859 XHC_GENERIC_TIMEOUT,\r
3860 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3861 );\r
260fbf53
EL
3862 if (EFI_ERROR (Status)) {\r
3863 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
3864 }\r
6b4483cd 3865 return Status;\r
3866}\r
3867\r
3868\r
92870c98 3869/**\r
3870 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
3871\r
a9292c13 3872 @param Xhc The XHCI Instance.\r
92870c98 3873 @param SlotId The slot id to be configured.\r
3874 @param PortNum The total number of downstream port supported by the hub.\r
3875 @param TTT The TT think time of the hub device.\r
3876 @param MTT The multi-TT of the hub device.\r
3877\r
3878 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
3879\r
3880**/\r
3881EFI_STATUS\r
3882XhcConfigHubContext (\r
a9292c13 3883 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 3884 IN UINT8 SlotId,\r
3885 IN UINT8 PortNum,\r
3886 IN UINT8 TTT,\r
3887 IN UINT8 MTT\r
3888 )\r
3889{\r
a9292c13 3890 EFI_STATUS Status;\r
a9292c13 3891 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3892 INPUT_CONTEXT *InputContext;\r
3893 DEVICE_CONTEXT *OutputContext;\r
3894 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1847ed0b 3895 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 3896\r
a9292c13 3897 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3898 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3899 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
92870c98 3900\r
3901 //\r
3902 // 4.6.7 Evaluate Context\r
3903 //\r
3904 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3905\r
3906 InputContext->InputControlContext.Dword2 |= BIT0;\r
3907\r
3908 //\r
3909 // Copy the slot context from OutputContext to Input context\r
3910 //\r
a9292c13 3911 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
92870c98 3912 InputContext->Slot.Hub = 1;\r
3913 InputContext->Slot.PortNum = PortNum;\r
3914 InputContext->Slot.TTT = TTT;\r
3915 InputContext->Slot.MTT = MTT;\r
3916\r
3917 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3918 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3919 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3920 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 3921 CmdTrbCfgEP.CycleBit = 1;\r
3922 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 3923 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 3924 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
3925 Status = XhcCmdTransfer (\r
3926 Xhc,\r
a9292c13 3927 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 3928 XHC_GENERIC_TIMEOUT,\r
a9292c13 3929 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 3930 );\r
260fbf53
EL
3931 if (EFI_ERROR (Status)) {\r
3932 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
3933 }\r
92870c98 3934 return Status;\r
3935}\r
3936\r
6b4483cd 3937/**\r
3938 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
3939\r
3940 @param Xhc The XHCI Instance.\r
3941 @param SlotId The slot id to be configured.\r
3942 @param PortNum The total number of downstream port supported by the hub.\r
3943 @param TTT The TT think time of the hub device.\r
3944 @param MTT The multi-TT of the hub device.\r
3945\r
3946 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
3947\r
3948**/\r
3949EFI_STATUS\r
3950XhcConfigHubContext64 (\r
3951 IN USB_XHCI_INSTANCE *Xhc,\r
3952 IN UINT8 SlotId,\r
3953 IN UINT8 PortNum,\r
3954 IN UINT8 TTT,\r
3955 IN UINT8 MTT\r
3956 )\r
3957{\r
3958 EFI_STATUS Status;\r
6b4483cd 3959 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3960 INPUT_CONTEXT_64 *InputContext;\r
3961 DEVICE_CONTEXT_64 *OutputContext;\r
3962 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1847ed0b 3963 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 3964\r
3965 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3966 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3967 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3968\r
3969 //\r
3970 // 4.6.7 Evaluate Context\r
3971 //\r
3972 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3973\r
3974 InputContext->InputControlContext.Dword2 |= BIT0;\r
3975\r
3976 //\r
3977 // Copy the slot context from OutputContext to Input context\r
3978 //\r
3979 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
3980 InputContext->Slot.Hub = 1;\r
3981 InputContext->Slot.PortNum = PortNum;\r
3982 InputContext->Slot.TTT = TTT;\r
3983 InputContext->Slot.MTT = MTT;\r
3984\r
3985 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3986 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3987 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3988 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 3989 CmdTrbCfgEP.CycleBit = 1;\r
3990 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3991 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3992 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
3993 Status = XhcCmdTransfer (\r
3994 Xhc,\r
3995 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3996 XHC_GENERIC_TIMEOUT,\r
3997 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3998 );\r
260fbf53
EL
3999 if (EFI_ERROR (Status)) {\r
4000 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
4001 }\r
6b4483cd 4002 return Status;\r
4003}\r
4004\r
4005\r