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