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