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