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