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