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