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