]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
EdkCompatibilityPkg: Fixed EDK Shell build
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
CommitLineData
92870c98 1/** @file\r
2\r
3 XHCI transfer scheduling routines.\r
4\r
ca243131 5Copyright (c) 2011 - 2013, 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
298 TrbStart->TrbCtrSetup.Lenth = 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
a9292c13 324 TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen;\r
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
a9292c13 390 TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
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
a9292c13 425 TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
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
528 Status = UsbHcAllocateAlignedPages (\r
529 Xhc->PciIo,\r
530 EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
531 Xhc->PageSize,\r
532 (VOID **) &ScratchBuf, \r
533 &ScratchPhy,\r
534 &Xhc->ScratchMap\r
535 );\r
536 ASSERT_EFI_ERROR (Status);\r
537\r
a9292c13 538 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
92870c98 539 Xhc->ScratchBuf = ScratchBuf;\r
540\r
1847ed0b
EL
541 //\r
542 // Allocate each scratch buffer\r
543 //\r
92870c98 544 for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
1847ed0b
EL
545 Status = UsbHcAllocateAlignedPages (\r
546 Xhc->PciIo,\r
547 EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
548 Xhc->PageSize,\r
549 (VOID **) &ScratchEntry[Index],\r
550 &ScratchEntryPhy,\r
551 (VOID **) &ScratchEntryMap[Index]\r
552 );\r
553 ASSERT_EFI_ERROR (Status);\r
554 ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);\r
555 //\r
556 // Fill with the PCI device address\r
557 //\r
558 *ScratchBuf++ = ScratchEntryPhy;\r
92870c98 559 }\r
92870c98 560 //\r
561 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
562 // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
563 //\r
1847ed0b 564 *(UINT64 *)Dcbaa = (UINT64)(UINTN) ScratchPhy;\r
92870c98 565 }\r
566\r
567 //\r
568 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
569 // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
570 //\r
a9292c13 571 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;\r
6b4483cd 572 //\r
573 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
574 // So divide it to two 32-bytes width register access.\r
575 //\r
1847ed0b
EL
576 DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Entries);\r
577 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT(DcbaaPhy));\r
578 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));\r
579\r
ce9b5900 580 DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));\r
92870c98 581\r
582 //\r
583 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
584 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
585 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
586 // always be '0'.\r
587 //\r
588 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
589 //\r
590 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
591 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
592 // So we set RCS as inverted PCS init value to let Command Ring empty\r
593 //\r
594 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;\r
1847ed0b
EL
595 CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, (VOID *)(UINTN) CmdRing, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
596 ASSERT ((CmdRingPhy & 0x3F) == 0);\r
597 CmdRingPhy |= XHC_CRCR_RCS;\r
6b4483cd 598 //\r
599 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
600 // So divide it to two 32-bytes width register access.\r
601 //\r
1847ed0b
EL
602 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRingPhy));\r
603 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
92870c98 604\r
605 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
606\r
607 //\r
608 // Disable the 'interrupter enable' bit in USB_CMD\r
609 // and clear IE & IP bit in all Interrupter X Management Registers.\r
610 //\r
611 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
612 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
613 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
614 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
615 }\r
616\r
617 //\r
618 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
619 //\r
6b4483cd 620 CreateEventRing (Xhc, &Xhc->EventRing);\r
621 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));\r
92870c98 622}\r
623\r
624/**\r
625 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
626 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
627 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
628 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
629 Stopped to the Running state.\r
630\r
a9292c13 631 @param Xhc The XHCI Instance.\r
92870c98 632 @param Urb The urb which makes the endpoint halted.\r
633\r
634 @retval EFI_SUCCESS The recovery is successful.\r
635 @retval Others Failed to recovery halted endpoint.\r
636\r
637**/\r
638EFI_STATUS\r
639EFIAPI\r
640XhcRecoverHaltedEndpoint (\r
a9292c13 641 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 642 IN URB *Urb\r
643 )\r
644{\r
a9292c13 645 EFI_STATUS Status;\r
646 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
647 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
648 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
649 UINT8 Dci;\r
650 UINT8 SlotId;\r
1847ed0b 651 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 652\r
6b4483cd 653 Status = EFI_SUCCESS;\r
654 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
655 if (SlotId == 0) {\r
656 return EFI_DEVICE_ERROR;\r
657 }\r
658 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
659 ASSERT (Dci < 32);\r
660 \r
92870c98 661 DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
662\r
663 //\r
664 // 1) Send Reset endpoint command to transit from halt to stop state\r
665 //\r
666 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
667 CmdTrbResetED.CycleBit = 1;\r
668 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
669 CmdTrbResetED.EDID = Dci;\r
670 CmdTrbResetED.SlotId = SlotId;\r
671 Status = XhcCmdTransfer (\r
672 Xhc,\r
a9292c13 673 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
92870c98 674 XHC_GENERIC_TIMEOUT,\r
a9292c13 675 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 676 );\r
260fbf53
EL
677 if (EFI_ERROR(Status)) {\r
678 DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
679 goto Done;\r
680 }\r
92870c98 681\r
682 //\r
683 // 2)Set dequeue pointer\r
684 //\r
685 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
1847ed0b
EL
686 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
687 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
688 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 689 CmdSetTRDeq.CycleBit = 1;\r
690 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
691 CmdSetTRDeq.Endpoint = Dci;\r
692 CmdSetTRDeq.SlotId = SlotId;\r
693 Status = XhcCmdTransfer (\r
694 Xhc,\r
a9292c13 695 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
92870c98 696 XHC_GENERIC_TIMEOUT,\r
a9292c13 697 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 698 );\r
260fbf53
EL
699 if (EFI_ERROR(Status)) {\r
700 DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
701 goto Done;\r
702 }\r
92870c98 703\r
704 //\r
705 // 3)Ring the doorbell to transit from stop to active\r
706 //\r
707 XhcRingDoorBell (Xhc, SlotId, Dci);\r
708\r
260fbf53 709Done:\r
92870c98 710 return Status;\r
711}\r
712\r
713/**\r
714 Create XHCI event ring.\r
715\r
a9292c13 716 @param Xhc The XHCI Instance.\r
92870c98 717 @param EventRing The created event ring.\r
718\r
719**/\r
720VOID\r
92870c98 721CreateEventRing (\r
a9292c13 722 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 723 OUT EVENT_RING *EventRing\r
724 )\r
725{\r
726 VOID *Buf;\r
727 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
1847ed0b
EL
728 UINTN Size;\r
729 EFI_PHYSICAL_ADDRESS ERSTPhy;\r
730 EFI_PHYSICAL_ADDRESS DequeuePhy;\r
92870c98 731\r
732 ASSERT (EventRing != NULL);\r
733\r
1847ed0b
EL
734 Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;\r
735 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
92870c98 736 ASSERT (Buf != NULL);\r
737 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
1847ed0b 738 ZeroMem (Buf, Size);\r
92870c98 739\r
740 EventRing->EventRingSeg0 = Buf;\r
92870c98 741 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
a9292c13 742 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
743 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
1847ed0b
EL
744 \r
745 DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
746 \r
92870c98 747 //\r
748 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
749 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
750 //\r
751 EventRing->EventRingCCS = 1;\r
752\r
1847ed0b
EL
753 Size = EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
754 Buf = UsbHcAllocateMem (Xhc->MemPool, Size);\r
92870c98 755 ASSERT (Buf != NULL);\r
756 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
1847ed0b 757 ZeroMem (Buf, Size);\r
92870c98 758\r
759 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
760 EventRing->ERSTBase = ERSTBase;\r
1847ed0b
EL
761 ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);\r
762 ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);\r
92870c98 763 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
764\r
1847ed0b
EL
765 ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, ERSTBase, Size);\r
766\r
92870c98 767 //\r
768 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
769 //\r
770 XhcWriteRuntimeReg (\r
771 Xhc,\r
6b4483cd 772 XHC_ERSTSZ_OFFSET,\r
92870c98 773 ERST_NUMBER\r
774 );\r
775 //\r
776 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
777 //\r
6b4483cd 778 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
779 // So divide it to two 32-bytes width register access.\r
780 //\r
781 XhcWriteRuntimeReg (\r
782 Xhc,\r
783 XHC_ERDP_OFFSET,\r
1847ed0b 784 XHC_LOW_32BIT((UINT64)(UINTN)DequeuePhy)\r
6b4483cd 785 );\r
786 XhcWriteRuntimeReg (\r
92870c98 787 Xhc,\r
6b4483cd 788 XHC_ERDP_OFFSET + 4,\r
1847ed0b 789 XHC_HIGH_32BIT((UINT64)(UINTN)DequeuePhy)\r
92870c98 790 );\r
791 //\r
792 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)\r
793 //\r
6b4483cd 794 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
795 // So divide it to two 32-bytes width register access.\r
796 //\r
797 XhcWriteRuntimeReg (\r
798 Xhc,\r
799 XHC_ERSTBA_OFFSET,\r
1847ed0b 800 XHC_LOW_32BIT((UINT64)(UINTN)ERSTPhy)\r
6b4483cd 801 );\r
802 XhcWriteRuntimeReg (\r
92870c98 803 Xhc,\r
6b4483cd 804 XHC_ERSTBA_OFFSET + 4,\r
1847ed0b 805 XHC_HIGH_32BIT((UINT64)(UINTN)ERSTPhy)\r
92870c98 806 );\r
807 //\r
808 // Need set IMAN IE bit to enble the ring interrupt\r
809 //\r
6b4483cd 810 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);\r
92870c98 811}\r
812\r
813/**\r
814 Create XHCI transfer ring.\r
815\r
a9292c13 816 @param Xhc The XHCI Instance.\r
92870c98 817 @param TrbNum The number of TRB in the ring.\r
818 @param TransferRing The created transfer ring.\r
819\r
820**/\r
821VOID\r
92870c98 822CreateTransferRing (\r
a9292c13 823 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 824 IN UINTN TrbNum,\r
825 OUT TRANSFER_RING *TransferRing\r
826 )\r
827{\r
828 VOID *Buf;\r
a9292c13 829 LINK_TRB *EndTrb;\r
1847ed0b 830 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 831\r
1847ed0b 832 Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);\r
92870c98 833 ASSERT (Buf != NULL);\r
834 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
a9292c13 835 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
92870c98 836\r
837 TransferRing->RingSeg0 = Buf;\r
838 TransferRing->TrbNumber = TrbNum;\r
a9292c13 839 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
840 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
92870c98 841 TransferRing->RingPCS = 1;\r
842 //\r
843 // 4.9.2 Transfer Ring Management\r
844 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
845 // point to the first TRB in the ring.\r
846 //\r
a9292c13 847 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
92870c98 848 EndTrb->Type = TRB_TYPE_LINK;\r
1847ed0b
EL
849 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
850 EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);\r
851 EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 852 //\r
853 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
854 //\r
855 EndTrb->TC = 1;\r
856 //\r
857 // Set Cycle bit as other TRB PCS init value\r
858 //\r
859 EndTrb->CycleBit = 0;\r
860}\r
861\r
862/**\r
863 Free XHCI event ring.\r
864\r
a9292c13 865 @param Xhc The XHCI Instance.\r
92870c98 866 @param EventRing The event ring to be freed.\r
867\r
868**/\r
869EFI_STATUS\r
870EFIAPI\r
871XhcFreeEventRing (\r
a9292c13 872 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 873 IN EVENT_RING *EventRing\r
874)\r
875{\r
92870c98 876 if(EventRing->EventRingSeg0 == NULL) {\r
877 return EFI_SUCCESS;\r
878 }\r
879\r
92870c98 880 //\r
1847ed0b 881 // Free EventRing Segment 0\r
92870c98 882 //\r
1847ed0b 883 UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
92870c98 884\r
885 //\r
1847ed0b 886 // Free ESRT table\r
92870c98 887 //\r
1847ed0b 888 UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
92870c98 889 return EFI_SUCCESS;\r
890}\r
891\r
892/**\r
893 Free the resouce allocated at initializing schedule.\r
894\r
a9292c13 895 @param Xhc The XHCI Instance.\r
92870c98 896\r
897**/\r
898VOID\r
899XhcFreeSched (\r
a9292c13 900 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 901 )\r
902{\r
1847ed0b
EL
903 UINT32 Index;\r
904 UINT64 *ScratchEntry;\r
905 \r
92870c98 906 if (Xhc->ScratchBuf != NULL) {\r
1847ed0b 907 ScratchEntry = Xhc->ScratchEntry;\r
92870c98 908 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
1847ed0b
EL
909 //\r
910 // Free Scratchpad Buffers\r
911 //\r
912 UsbHcFreeAlignedPages (Xhc->PciIo, (VOID*)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);\r
92870c98 913 }\r
1847ed0b
EL
914 //\r
915 // Free Scratchpad Buffer Array\r
916 //\r
917 UsbHcFreeAlignedPages (Xhc->PciIo, Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);\r
918 FreePool (Xhc->ScratchEntryMap);\r
919 FreePool (Xhc->ScratchEntry);\r
920 }\r
921\r
922 if (Xhc->CmdRing.RingSeg0 != NULL) {\r
923 UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
924 Xhc->CmdRing.RingSeg0 = NULL;\r
92870c98 925 }\r
1847ed0b
EL
926 \r
927 XhcFreeEventRing (Xhc,&Xhc->EventRing);\r
92870c98 928\r
929 if (Xhc->DCBAA != NULL) {\r
1847ed0b 930 UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof(UINT64));\r
92870c98 931 Xhc->DCBAA = NULL;\r
932 }\r
1847ed0b
EL
933 \r
934 //\r
935 // Free memory pool at last\r
936 //\r
937 if (Xhc->MemPool != NULL) {\r
938 UsbHcFreeMemPool (Xhc->MemPool);\r
939 Xhc->MemPool = NULL;\r
92870c98 940 }\r
92870c98 941}\r
942\r
943/**\r
a50f7c4c 944 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.\r
945\r
946 @param Xhc The XHCI Instance.\r
947 @param Trb The TRB to be checked.\r
948 @param Urb The pointer to the matched Urb.\r
949\r
950 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.\r
951 @retval FALSE The Trb is not matched with any URBs in the async list.\r
952\r
953**/\r
954BOOLEAN\r
955IsAsyncIntTrb (\r
956 IN USB_XHCI_INSTANCE *Xhc,\r
957 IN TRB_TEMPLATE *Trb,\r
958 OUT URB **Urb\r
959 )\r
960{\r
961 LIST_ENTRY *Entry;\r
962 LIST_ENTRY *Next;\r
963 TRB_TEMPLATE *CheckedTrb;\r
964 URB *CheckedUrb;\r
965 UINTN Index;\r
966\r
967 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
968 CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
969 CheckedTrb = CheckedUrb->TrbStart;\r
970 for (Index = 0; Index < CheckedUrb->TrbNum; Index++) {\r
971 if (Trb == CheckedTrb) {\r
972 *Urb = CheckedUrb;\r
973 return TRUE;\r
974 }\r
975 CheckedTrb++;\r
976 if ((UINTN)CheckedTrb >= ((UINTN) CheckedUrb->Ring->RingSeg0 + sizeof (TRB_TEMPLATE) * CheckedUrb->Ring->TrbNumber)) {\r
977 CheckedTrb = (TRB_TEMPLATE*) CheckedUrb->Ring->RingSeg0;\r
978 }\r
979 }\r
980 }\r
981\r
982 return FALSE;\r
983}\r
984\r
985/**\r
986 Check if the Trb is a transaction of the URB.\r
92870c98 987\r
a50f7c4c 988 @param Trb The TRB to be checked\r
989 @param Urb The transfer ring to be checked.\r
92870c98 990\r
a50f7c4c 991 @retval TRUE It is a transaction of the URB.\r
992 @retval FALSE It is not any transaction of the URB.\r
92870c98 993\r
994**/\r
995BOOLEAN\r
996IsTransferRingTrb (\r
a50f7c4c 997 IN TRB_TEMPLATE *Trb,\r
998 IN URB *Urb\r
92870c98 999 )\r
1000{\r
a50f7c4c 1001 TRB_TEMPLATE *CheckedTrb;\r
92870c98 1002 UINTN Index;\r
1003\r
a50f7c4c 1004 CheckedTrb = Urb->Ring->RingSeg0;\r
92870c98 1005\r
a50f7c4c 1006 ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
92870c98 1007\r
a50f7c4c 1008 for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {\r
1009 if (Trb == CheckedTrb) {\r
1010 return TRUE;\r
92870c98 1011 }\r
a50f7c4c 1012 CheckedTrb++;\r
92870c98 1013 }\r
1014\r
a50f7c4c 1015 return FALSE;\r
92870c98 1016}\r
1017\r
1018/**\r
1019 Check the URB's execution result and update the URB's\r
1020 result accordingly.\r
1021\r
a9292c13 1022 @param Xhc The XHCI Instance.\r
92870c98 1023 @param Urb The URB to check result.\r
1024\r
1025 @return Whether the result of URB transfer is finialized.\r
1026\r
1027**/\r
1028EFI_STATUS\r
1029XhcCheckUrbResult (\r
a9292c13 1030 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1031 IN URB *Urb\r
1032 )\r
1033{\r
92870c98 1034 EVT_TRB_TRANSFER *EvtTrb;\r
a9292c13 1035 TRB_TEMPLATE *TRBPtr;\r
92870c98 1036 UINTN Index;\r
1037 UINT8 TRBType;\r
1038 EFI_STATUS Status;\r
a50f7c4c 1039 URB *AsyncUrb;\r
1040 URB *CheckedUrb;\r
1041 UINT64 XhcDequeue;\r
1042 UINT32 High;\r
1043 UINT32 Low;\r
1847ed0b 1044 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 1045\r
1046 ASSERT ((Xhc != NULL) && (Urb != NULL));\r
1047\r
09e4dbeb 1048 Status = EFI_SUCCESS;\r
1049 AsyncUrb = NULL;\r
a50f7c4c 1050\r
1051 if (Urb->Finished) {\r
1052 goto EXIT;\r
1053 }\r
1054\r
1055 EvtTrb = NULL;\r
92870c98 1056\r
1057 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
1058 Urb->Result |= EFI_USB_ERR_SYSTEM;\r
1059 Status = EFI_DEVICE_ERROR;\r
1060 goto EXIT;\r
1061 }\r
1062\r
1063 //\r
a50f7c4c 1064 // Traverse the event ring to find out all new events from the previous check.\r
92870c98 1065 //\r
a50f7c4c 1066 XhcSyncEventRing (Xhc, &Xhc->EventRing);\r
1067 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {\r
1068 Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));\r
92870c98 1069 if (Status == EFI_NOT_READY) {\r
a50f7c4c 1070 //\r
1071 // All new events are handled, return directly.\r
1072 //\r
92870c98 1073 goto EXIT;\r
1074 }\r
1075\r
6b4483cd 1076 //\r
1077 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.\r
1078 //\r
1079 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
1080 continue;\r
1081 }\r
1847ed0b
EL
1082 \r
1083 //\r
1084 // Need convert pci device address to host address\r
1085 //\r
1086 PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64) EvtTrb->TRBPtrHi, 32));\r
1087 TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
92870c98 1088\r
a50f7c4c 1089 //\r
1090 // Update the status of Urb according to the finished event regardless of whether\r
1091 // the urb is current checked one or in the XHCI's async transfer list.\r
1092 // This way is used to avoid that those completed async transfer events don't get\r
1093 // handled in time and are flushed by newer coming events.\r
1094 //\r
1095 if (IsTransferRingTrb (TRBPtr, Urb)) {\r
1096 CheckedUrb = Urb;\r
1097 } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) { \r
1098 CheckedUrb = AsyncUrb;\r
1099 } else {\r
1100 continue;\r
1101 }\r
1102 \r
1103 switch (EvtTrb->Completecode) {\r
1104 case TRB_COMPLETION_STALL_ERROR:\r
1105 CheckedUrb->Result |= EFI_USB_ERR_STALL;\r
1106 CheckedUrb->Finished = TRUE;\r
1107 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
1108 break;\r
92870c98 1109\r
a50f7c4c 1110 case TRB_COMPLETION_BABBLE_ERROR:\r
1111 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;\r
1112 CheckedUrb->Finished = TRUE;\r
1113 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
1114 break;\r
6b4483cd 1115\r
a50f7c4c 1116 case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
1117 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;\r
1118 CheckedUrb->Finished = TRUE;\r
1119 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));\r
6b4483cd 1120 break;\r
a50f7c4c 1121\r
1122 case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
1123 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1124 CheckedUrb->Finished = TRUE;\r
1125 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
1126 break;\r
1127\r
1128 case TRB_COMPLETION_SHORT_PACKET:\r
1129 case TRB_COMPLETION_SUCCESS:\r
1130 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
1131 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));\r
1132 }\r
1133\r
1134 TRBType = (UINT8) (TRBPtr->Type);\r
1135 if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
1136 (TRBType == TRB_TYPE_NORMAL) ||\r
1137 (TRBType == TRB_TYPE_ISOCH)) {\r
1138 CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Lenth);\r
1139 }\r
1140\r
1141 break;\r
1142\r
1143 default:\r
1144 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));\r
1145 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1146 CheckedUrb->Finished = TRUE;\r
1147 break;\r
1148 }\r
1149\r
1150 //\r
1151 // Only check first and end Trb event address\r
1152 //\r
1153 if (TRBPtr == CheckedUrb->TrbStart) {\r
1154 CheckedUrb->StartDone = TRUE;\r
1155 }\r
1156\r
1157 if (TRBPtr == CheckedUrb->TrbEnd) {\r
1158 CheckedUrb->EndDone = TRUE;\r
1159 }\r
1160\r
1161 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {\r
1162 CheckedUrb->Finished = TRUE;\r
1163 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;\r
92870c98 1164 }\r
1165 }\r
1166\r
1167EXIT:\r
a50f7c4c 1168\r
1169 //\r
1170 // Advance event ring to last available entry\r
1171 //\r
1172 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1173 // So divide it to two 32-bytes width register access.\r
1174 //\r
1175 Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);\r
1176 High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);\r
1177 XhcDequeue = (UINT64)(LShiftU64((UINT64)High, 32) | Low);\r
1178\r
1847ed0b
EL
1179 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));\r
1180\r
1181 if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {\r
a50f7c4c 1182 //\r
1183 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1184 // So divide it to two 32-bytes width register access.\r
1185 //\r
1847ed0b
EL
1186 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);\r
1187 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
a50f7c4c 1188 }\r
1189\r
92870c98 1190 return Status;\r
1191}\r
1192\r
1193\r
1194/**\r
1195 Execute the transfer by polling the URB. This is a synchronous operation.\r
1196\r
a9292c13 1197 @param Xhc The XHCI Instance.\r
92870c98 1198 @param CmdTransfer The executed URB is for cmd transfer or not.\r
1199 @param Urb The URB to execute.\r
a9292c13 1200 @param Timeout The time to wait before abort, in millisecond.\r
92870c98 1201\r
1202 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
1203 @return EFI_TIMEOUT The transfer failed due to time out.\r
1204 @return EFI_SUCCESS The transfer finished OK.\r
1205\r
1206**/\r
1207EFI_STATUS\r
1208XhcExecTransfer (\r
a9292c13 1209 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1210 IN BOOLEAN CmdTransfer,\r
1211 IN URB *Urb,\r
a9292c13 1212 IN UINTN Timeout\r
92870c98 1213 )\r
1214{\r
1215 EFI_STATUS Status;\r
1216 UINTN Index;\r
1217 UINTN Loop;\r
1218 UINT8 SlotId;\r
1219 UINT8 Dci;\r
1220\r
1221 if (CmdTransfer) {\r
1222 SlotId = 0;\r
1223 Dci = 0;\r
1224 } else {\r
6b4483cd 1225 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1226 if (SlotId == 0) {\r
1227 return EFI_DEVICE_ERROR;\r
1228 }\r
1229 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
1230 ASSERT (Dci < 32);\r
92870c98 1231 }\r
1232\r
1233 Status = EFI_SUCCESS;\r
ca243131 1234 Loop = Timeout * XHC_1_MILLISECOND;\r
a9292c13 1235 if (Timeout == 0) {\r
92870c98 1236 Loop = 0xFFFFFFFF;\r
1237 }\r
1238\r
1239 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1240\r
1241 for (Index = 0; Index < Loop; Index++) {\r
1242 Status = XhcCheckUrbResult (Xhc, Urb);\r
a50f7c4c 1243 if (Urb->Finished) {\r
92870c98 1244 break;\r
1245 }\r
ca243131 1246 gBS->Stall (XHC_1_MICROSECOND);\r
92870c98 1247 }\r
1248\r
a50f7c4c 1249 if (Index == Loop) {\r
1250 Urb->Result = EFI_USB_ERR_TIMEOUT;\r
1251 }\r
1252\r
92870c98 1253 return Status;\r
1254}\r
1255\r
1256/**\r
1257 Delete a single asynchronous interrupt transfer for\r
1258 the device and endpoint.\r
1259\r
a9292c13 1260 @param Xhc The XHCI Instance.\r
6b4483cd 1261 @param BusAddr The logical device address assigned by UsbBus driver.\r
92870c98 1262 @param EpNum The endpoint of the target.\r
1263\r
1264 @retval EFI_SUCCESS An asynchronous transfer is removed.\r
1265 @retval EFI_NOT_FOUND No transfer for the device is found.\r
1266\r
1267**/\r
1268EFI_STATUS\r
1269XhciDelAsyncIntTransfer (\r
a9292c13 1270 IN USB_XHCI_INSTANCE *Xhc,\r
6b4483cd 1271 IN UINT8 BusAddr,\r
92870c98 1272 IN UINT8 EpNum\r
1273 )\r
1274{\r
1275 LIST_ENTRY *Entry;\r
1276 LIST_ENTRY *Next;\r
1277 URB *Urb;\r
1278 EFI_USB_DATA_DIRECTION Direction;\r
92870c98 1279\r
1280 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
1281 EpNum &= 0x0F;\r
1282\r
6b4483cd 1283 Urb = NULL;\r
92870c98 1284\r
1285 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1286 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
6b4483cd 1287 if ((Urb->Ep.BusAddr == BusAddr) &&\r
92870c98 1288 (Urb->Ep.EpAddr == EpNum) &&\r
1289 (Urb->Ep.Direction == Direction)) {\r
1290 RemoveEntryList (&Urb->UrbList);\r
1291 FreePool (Urb->Data);\r
1847ed0b 1292 XhcFreeUrb (Xhc, Urb);\r
92870c98 1293 return EFI_SUCCESS;\r
1294 }\r
1295 }\r
1296\r
1297 return EFI_NOT_FOUND;\r
1298}\r
1299\r
1300/**\r
1301 Remove all the asynchronous interrutp transfers.\r
1302\r
a9292c13 1303 @param Xhc The XHCI Instance.\r
92870c98 1304\r
1305**/\r
1306VOID\r
1307XhciDelAllAsyncIntTransfers (\r
a9292c13 1308 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 1309 )\r
1310{\r
1311 LIST_ENTRY *Entry;\r
1312 LIST_ENTRY *Next;\r
1313 URB *Urb;\r
1314\r
1315 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1316 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1317 RemoveEntryList (&Urb->UrbList);\r
1318 FreePool (Urb->Data);\r
1847ed0b 1319 XhcFreeUrb (Xhc, Urb);\r
92870c98 1320 }\r
1321}\r
1322\r
1323/**\r
1324 Update the queue head for next round of asynchronous transfer\r
1325\r
a9292c13 1326 @param Xhc The XHCI Instance.\r
92870c98 1327 @param Urb The URB to update\r
1328\r
1329**/\r
1330VOID\r
1331XhcUpdateAsyncRequest (\r
a9292c13 1332 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1333 IN URB *Urb\r
1334 )\r
1335{\r
1336 EFI_STATUS Status;\r
1337\r
1338 if (Urb->Result == EFI_USB_NOERROR) {\r
1339 Status = XhcCreateTransferTrb (Xhc, Urb);\r
6b4483cd 1340 if (EFI_ERROR (Status)) {\r
1341 return;\r
1342 }\r
92870c98 1343 Status = RingIntTransferDoorBell (Xhc, Urb);\r
6b4483cd 1344 if (EFI_ERROR (Status)) {\r
1345 return;\r
1346 }\r
92870c98 1347 }\r
1348}\r
1349\r
1847ed0b
EL
1350/**\r
1351 Flush data from PCI controller specific address to mapped system\r
1352 memory address.\r
1353\r
1354 @param Xhc The XHCI device.\r
1355 @param Urb The URB to unmap.\r
1356\r
1357 @retval EFI_SUCCESS Success to flush data to mapped system memory.\r
1358 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.\r
1359\r
1360**/\r
1361EFI_STATUS\r
1362XhcFlushAsyncIntMap (\r
1363 IN USB_XHCI_INSTANCE *Xhc,\r
1364 IN URB *Urb\r
1365 )\r
1366{\r
1367 EFI_STATUS Status;\r
1368 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1369 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
1370 EFI_PCI_IO_PROTOCOL *PciIo;\r
1371 UINTN Len;\r
1372 VOID *Map;\r
1373\r
1374 PciIo = Xhc->PciIo;\r
1375 Len = Urb->DataLen;\r
1376\r
1377 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
1378 MapOp = EfiPciIoOperationBusMasterWrite;\r
1379 } else {\r
1380 MapOp = EfiPciIoOperationBusMasterRead;\r
1381 }\r
1382\r
1383 if (Urb->DataMap != NULL) {\r
1384 Status = PciIo->Unmap (PciIo, Urb->DataMap);\r
1385 if (EFI_ERROR (Status)) {\r
1386 goto ON_ERROR;\r
1387 }\r
1388 }\r
1389\r
1390 Urb->DataMap = NULL;\r
1391\r
1392 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
1393 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
1394 goto ON_ERROR;\r
1395 }\r
1396\r
1397 Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
1398 Urb->DataMap = Map;\r
1399 return EFI_SUCCESS;\r
1400\r
1401ON_ERROR:\r
1402 return EFI_DEVICE_ERROR;\r
1403}\r
92870c98 1404\r
1405/**\r
1406 Interrupt transfer periodic check handler.\r
1407\r
1408 @param Event Interrupt event.\r
a9292c13 1409 @param Context Pointer to USB_XHCI_INSTANCE.\r
92870c98 1410\r
1411**/\r
1412VOID\r
1413EFIAPI\r
1414XhcMonitorAsyncRequests (\r
1415 IN EFI_EVENT Event,\r
1416 IN VOID *Context\r
1417 )\r
1418{\r
a9292c13 1419 USB_XHCI_INSTANCE *Xhc;\r
92870c98 1420 LIST_ENTRY *Entry;\r
1421 LIST_ENTRY *Next;\r
1422 UINT8 *ProcBuf;\r
1423 URB *Urb;\r
1424 UINT8 SlotId;\r
1847ed0b 1425 EFI_STATUS Status;\r
92870c98 1426 EFI_TPL OldTpl;\r
1427\r
1428 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1429\r
a9292c13 1430 Xhc = (USB_XHCI_INSTANCE*) Context;\r
92870c98 1431\r
1432 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1433 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1434\r
1435 //\r
1436 // Make sure that the device is available before every check.\r
1437 //\r
6b4483cd 1438 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
92870c98 1439 if (SlotId == 0) {\r
1440 continue;\r
1441 }\r
1442\r
1443 //\r
1444 // Check the result of URB execution. If it is still\r
1445 // active, check the next one.\r
1446 //\r
b6cb9c39 1447 XhcCheckUrbResult (Xhc, Urb);\r
92870c98 1448\r
a50f7c4c 1449 if (!Urb->Finished) {\r
92870c98 1450 continue;\r
1451 }\r
1452\r
1847ed0b
EL
1453 //\r
1454 // Flush any PCI posted write transactions from a PCI host\r
1455 // bridge to system memory.\r
1456 //\r
1457 Status = XhcFlushAsyncIntMap (Xhc, Urb);\r
1458 if (EFI_ERROR (Status)) {\r
1459 DEBUG ((EFI_D_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));\r
1460 }\r
1461\r
92870c98 1462 //\r
1463 // Allocate a buffer then copy the transferred data for user.\r
1464 // If failed to allocate the buffer, update the URB for next\r
1465 // round of transfer. Ignore the data of this round.\r
1466 //\r
1467 ProcBuf = NULL;\r
1468 if (Urb->Result == EFI_USB_NOERROR) {\r
1469 ASSERT (Urb->Completed <= Urb->DataLen);\r
1470\r
a9292c13 1471 ProcBuf = AllocateZeroPool (Urb->Completed);\r
92870c98 1472\r
1473 if (ProcBuf == NULL) {\r
1474 XhcUpdateAsyncRequest (Xhc, Urb);\r
1475 continue;\r
1476 }\r
1477\r
1478 CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
1479 }\r
1480\r
92870c98 1481 //\r
1482 // Leave error recovery to its related device driver. A\r
1483 // common case of the error recovery is to re-submit the\r
1484 // interrupt transfer which is linked to the head of the\r
1485 // list. This function scans from head to tail. So the\r
1486 // re-submitted interrupt transfer's callback function\r
1487 // will not be called again in this round. Don't touch this\r
1488 // URB after the callback, it may have been removed by the\r
1489 // callback.\r
1490 //\r
1491 if (Urb->Callback != NULL) {\r
1492 //\r
1493 // Restore the old TPL, USB bus maybe connect device in\r
1494 // his callback. Some drivers may has a lower TPL restriction.\r
1495 //\r
1496 gBS->RestoreTPL (OldTpl);\r
1497 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
1498 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1499 }\r
1500\r
1501 if (ProcBuf != NULL) {\r
1502 gBS->FreePool (ProcBuf);\r
1503 }\r
a50f7c4c 1504\r
1505 XhcUpdateAsyncRequest (Xhc, Urb);\r
92870c98 1506 }\r
1507 gBS->RestoreTPL (OldTpl);\r
1508}\r
1509\r
1510/**\r
1511 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
1512\r
a9292c13 1513 @param Xhc The XHCI Instance.\r
92870c98 1514 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
1515 @param Port The port to be polled.\r
1516 @param PortState The port state.\r
1517\r
1518 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
1519 @retval Others Should not appear.\r
1520\r
1521**/\r
1522EFI_STATUS\r
1523EFIAPI\r
1524XhcPollPortStatusChange (\r
a9292c13 1525 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1526 IN USB_DEV_ROUTE ParentRouteChart,\r
1527 IN UINT8 Port,\r
1528 IN EFI_USB_PORT_STATUS *PortState\r
1529 )\r
1530{\r
1531 EFI_STATUS Status;\r
1532 UINT8 Speed;\r
1533 UINT8 SlotId;\r
1534 USB_DEV_ROUTE RouteChart;\r
1535\r
1536 Status = EFI_SUCCESS;\r
1537\r
1538 if (ParentRouteChart.Dword == 0) {\r
a9292c13 1539 RouteChart.Route.RouteString = 0;\r
1540 RouteChart.Route.RootPortNum = Port + 1;\r
1541 RouteChart.Route.TierNum = 1;\r
92870c98 1542 } else {\r
1543 if(Port < 14) {\r
a9292c13 1544 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1545 } else {\r
a9292c13 1546 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1547 }\r
a9292c13 1548 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
1549 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
92870c98 1550 }\r
1551\r
1552 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1553 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
1554 //\r
1555 // Has a device attached, Identify device speed after port is enabled.\r
1556 //\r
1557 Speed = EFI_USB_SPEED_FULL;\r
1558 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
1559 Speed = EFI_USB_SPEED_LOW;\r
1560 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
1561 Speed = EFI_USB_SPEED_HIGH;\r
1562 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
1563 Speed = EFI_USB_SPEED_SUPER;\r
1564 }\r
1565 //\r
1566 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
1567 //\r
a9292c13 1568 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
92870c98 1569 if (SlotId == 0) {\r
6b4483cd 1570 if (Xhc->HcCParams.Data.Csz == 0) {\r
1571 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1572 } else {\r
1573 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1574 }\r
92870c98 1575 }\r
1576 } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {\r
1577 //\r
1578 // Device is detached. Disable the allocated device slot and release resource.\r
1579 //\r
a9292c13 1580 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
92870c98 1581 if (SlotId != 0) {\r
6b4483cd 1582 if (Xhc->HcCParams.Data.Csz == 0) {\r
1583 Status = XhcDisableSlotCmd (Xhc, SlotId);\r
1584 } else {\r
1585 Status = XhcDisableSlotCmd64 (Xhc, SlotId);\r
1586 }\r
92870c98 1587 }\r
1588 }\r
1589 return Status;\r
1590}\r
1591\r
1592\r
1593/**\r
1594 Calculate the device context index by endpoint address and direction.\r
1595\r
1596 @param EpAddr The target endpoint number.\r
1597 @param Direction The direction of the target endpoint.\r
1598\r
1599 @return The device context index of endpoint.\r
1600\r
1601**/\r
1602UINT8\r
1603XhcEndpointToDci (\r
1604 IN UINT8 EpAddr,\r
1605 IN UINT8 Direction\r
1606 )\r
1607{\r
1608 UINT8 Index;\r
1609\r
1610 if (EpAddr == 0) {\r
1611 return 1;\r
1612 } else {\r
ce9b5900 1613 Index = (UINT8) (2 * EpAddr);\r
92870c98 1614 if (Direction == EfiUsbDataIn) {\r
1615 Index += 1;\r
1616 }\r
1617 return Index;\r
1618 }\r
1619}\r
1620\r
92870c98 1621/**\r
1622 Find out the actual device address according to the requested device address from UsbBus.\r
1623\r
a9292c13 1624 @param Xhc The XHCI Instance.\r
1625 @param BusDevAddr The requested device address by UsbBus upper driver.\r
92870c98 1626\r
1627 @return The actual device address assigned to the device.\r
1628\r
1629**/\r
1630UINT8\r
1631EFIAPI\r
1632XhcBusDevAddrToSlotId (\r
a9292c13 1633 IN USB_XHCI_INSTANCE *Xhc,\r
1634 IN UINT8 BusDevAddr\r
92870c98 1635 )\r
1636{\r
1637 UINT8 Index;\r
1638\r
1639 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1640 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1641 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1642 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
92870c98 1643 break;\r
1644 }\r
1645 }\r
1646\r
1647 if (Index == 255) {\r
1648 return 0;\r
1649 }\r
1650\r
a9292c13 1651 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1652}\r
1653\r
1654/**\r
1655 Find out the slot id according to the device's route string.\r
1656\r
a9292c13 1657 @param Xhc The XHCI Instance.\r
1658 @param RouteString The route string described the device location.\r
92870c98 1659\r
1660 @return The slot id used by the device.\r
1661\r
1662**/\r
1663UINT8\r
1664EFIAPI\r
1665XhcRouteStringToSlotId (\r
a9292c13 1666 IN USB_XHCI_INSTANCE *Xhc,\r
1667 IN USB_DEV_ROUTE RouteString\r
92870c98 1668 )\r
1669{\r
1670 UINT8 Index;\r
1671\r
1672 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1673 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1674 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1675 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
92870c98 1676 break;\r
1677 }\r
1678 }\r
1679\r
1680 if (Index == 255) {\r
1681 return 0;\r
1682 }\r
1683\r
a9292c13 1684 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1685}\r
1686\r
1687/**\r
1688 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
1689\r
a9292c13 1690 @param Xhc The XHCI Instance.\r
92870c98 1691 @param EvtRing The event ring to sync.\r
1692\r
1693 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
1694\r
1695**/\r
1696EFI_STATUS\r
1697EFIAPI\r
1698XhcSyncEventRing (\r
a9292c13 1699 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1700 IN EVENT_RING *EvtRing\r
1701 )\r
1702{\r
1703 UINTN Index;\r
a9292c13 1704 TRB_TEMPLATE *EvtTrb1;\r
92870c98 1705\r
1706 ASSERT (EvtRing != NULL);\r
1707\r
1708 //\r
1709 // Calculate the EventRingEnqueue and EventRingCCS.\r
1710 // Note: only support single Segment\r
1711 //\r
a50f7c4c 1712 EvtTrb1 = EvtRing->EventRingDequeue;\r
92870c98 1713\r
1714 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
a50f7c4c 1715 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {\r
92870c98 1716 break;\r
1717 }\r
a50f7c4c 1718\r
92870c98 1719 EvtTrb1++;\r
a50f7c4c 1720\r
1721 if ((UINTN)EvtTrb1 >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
1722 EvtTrb1 = EvtRing->EventRingSeg0;\r
1723 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
1724 }\r
92870c98 1725 }\r
1726\r
1727 if (Index < EvtRing->TrbNumber) {\r
1728 EvtRing->EventRingEnqueue = EvtTrb1;\r
92870c98 1729 } else {\r
a50f7c4c 1730 ASSERT (FALSE);\r
92870c98 1731 }\r
1732\r
1733 return EFI_SUCCESS;\r
1734}\r
1735\r
1736/**\r
1737 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
1738\r
a9292c13 1739 @param Xhc The XHCI Instance.\r
92870c98 1740 @param TrsRing The transfer ring to sync.\r
1741\r
1742 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
1743\r
1744**/\r
1745EFI_STATUS\r
1746EFIAPI\r
1747XhcSyncTrsRing (\r
a9292c13 1748 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1749 IN TRANSFER_RING *TrsRing\r
1750 )\r
1751{\r
1752 UINTN Index;\r
a9292c13 1753 TRB_TEMPLATE *TrsTrb;\r
92870c98 1754\r
1755 ASSERT (TrsRing != NULL);\r
1756 //\r
1757 // Calculate the latest RingEnqueue and RingPCS\r
1758 //\r
1759 TrsTrb = TrsRing->RingEnqueue;\r
1760 ASSERT (TrsTrb != NULL);\r
1761\r
1762 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
1763 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
1764 break;\r
1765 }\r
1766 TrsTrb++;\r
1767 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
a9292c13 1768 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);\r
92870c98 1769 //\r
1770 // set cycle bit in Link TRB as normal\r
1771 //\r
a9292c13 1772 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
92870c98 1773 //\r
1774 // Toggle PCS maintained by software\r
1775 //\r
1776 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
1847ed0b 1777 TrsTrb = (TRB_TEMPLATE *) TrsRing->RingSeg0; // Use host address\r
92870c98 1778 }\r
1779 }\r
1780\r
1781 ASSERT (Index != TrsRing->TrbNumber);\r
1782\r
1783 if (TrsTrb != TrsRing->RingEnqueue) {\r
1784 TrsRing->RingEnqueue = TrsTrb;\r
1785 }\r
1786\r
1787 //\r
1788 // Clear the Trb context for enqueue, but reserve the PCS bit\r
1789 //\r
a9292c13 1790 TrsTrb->Parameter1 = 0;\r
1791 TrsTrb->Parameter2 = 0;\r
1792 TrsTrb->Status = 0;\r
1793 TrsTrb->RsvdZ1 = 0;\r
1794 TrsTrb->Type = 0;\r
1795 TrsTrb->Control = 0;\r
92870c98 1796\r
1797 return EFI_SUCCESS;\r
1798}\r
1799\r
1800/**\r
1801 Check if there is a new generated event.\r
1802\r
a9292c13 1803 @param Xhc The XHCI Instance.\r
92870c98 1804 @param EvtRing The event ring to check.\r
1805 @param NewEvtTrb The new event TRB found.\r
1806\r
1807 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
1808 @retval EFI_NOT_READY The event ring has no new event.\r
1809\r
1810**/\r
1811EFI_STATUS\r
1812EFIAPI\r
1813XhcCheckNewEvent (\r
a9292c13 1814 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1815 IN EVENT_RING *EvtRing,\r
a9292c13 1816 OUT TRB_TEMPLATE **NewEvtTrb\r
92870c98 1817 )\r
1818{\r
92870c98 1819 ASSERT (EvtRing != NULL);\r
1820\r
92870c98 1821 *NewEvtTrb = EvtRing->EventRingDequeue;\r
1822\r
1823 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
1824 return EFI_NOT_READY;\r
1825 }\r
1826\r
92870c98 1827 EvtRing->EventRingDequeue++;\r
1828 //\r
1829 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
1830 //\r
a50f7c4c 1831 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
92870c98 1832 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
1833 }\r
1834\r
b6cb9c39 1835 return EFI_SUCCESS;\r
92870c98 1836}\r
1837\r
1838/**\r
1839 Ring the door bell to notify XHCI there is a transaction to be executed.\r
1840\r
a9292c13 1841 @param Xhc The XHCI Instance.\r
92870c98 1842 @param SlotId The slot id of the target device.\r
1843 @param Dci The device context index of the target slot or endpoint.\r
1844\r
1845 @retval EFI_SUCCESS Successfully ring the door bell.\r
1846\r
1847**/\r
1848EFI_STATUS\r
1849EFIAPI\r
1850XhcRingDoorBell (\r
a9292c13 1851 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1852 IN UINT8 SlotId,\r
1853 IN UINT8 Dci\r
1854 )\r
1855{\r
1856 if (SlotId == 0) {\r
1857 XhcWriteDoorBellReg (Xhc, 0, 0);\r
1858 } else {\r
1859 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
1860 }\r
1861\r
1862 return EFI_SUCCESS;\r
1863}\r
1864\r
1865/**\r
1866 Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
1867\r
a9292c13 1868 @param Xhc The XHCI Instance.\r
92870c98 1869 @param Urb The URB to be rung.\r
1870\r
1871 @retval EFI_SUCCESS Successfully ring the door bell.\r
1872\r
1873**/\r
1874EFI_STATUS\r
1875RingIntTransferDoorBell (\r
a9292c13 1876 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1877 IN URB *Urb\r
1878 )\r
1879{\r
1880 UINT8 SlotId;\r
1881 UINT8 Dci;\r
1882\r
6b4483cd 1883 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1884 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
92870c98 1885 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1886 return EFI_SUCCESS;\r
1887}\r
1888\r
1889/**\r
1890 Assign and initialize the device slot for a new device.\r
1891\r
a9292c13 1892 @param Xhc The XHCI Instance.\r
92870c98 1893 @param ParentRouteChart The route string pointed to the parent device.\r
1894 @param ParentPort The port at which the device is located.\r
1895 @param RouteChart The route string pointed to the device.\r
1896 @param DeviceSpeed The device speed.\r
1897\r
1898 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
1899\r
1900**/\r
1901EFI_STATUS\r
1902EFIAPI\r
1903XhcInitializeDeviceSlot (\r
a9292c13 1904 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1905 IN USB_DEV_ROUTE ParentRouteChart,\r
1906 IN UINT16 ParentPort,\r
1907 IN USB_DEV_ROUTE RouteChart,\r
1908 IN UINT8 DeviceSpeed\r
1909 )\r
1910{\r
a9292c13 1911 EFI_STATUS Status;\r
1912 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1913 INPUT_CONTEXT *InputContext;\r
1914 DEVICE_CONTEXT *OutputContext;\r
1915 TRANSFER_RING *EndpointTransferRing;\r
1916 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
1917 UINT8 DeviceAddress;\r
1918 CMD_TRB_ENABLE_SLOT CmdTrb;\r
1919 UINT8 SlotId;\r
1920 UINT8 ParentSlotId;\r
1921 DEVICE_CONTEXT *ParentDeviceContext;\r
1847ed0b 1922 EFI_PHYSICAL_ADDRESS PhyAddr;\r
a9292c13 1923\r
1924 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
92870c98 1925 CmdTrb.CycleBit = 1;\r
1926 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
1927\r
1928 Status = XhcCmdTransfer (\r
1929 Xhc,\r
a9292c13 1930 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
92870c98 1931 XHC_GENERIC_TIMEOUT,\r
a9292c13 1932 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 1933 );\r
260fbf53
EL
1934 if (EFI_ERROR (Status)) {\r
1935 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
1936 return Status;\r
1937 }\r
92870c98 1938 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
1939 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
1940 SlotId = (UINT8)EvtTrb->SlotId;\r
1941 ASSERT (SlotId != 0);\r
1942\r
a9292c13 1943 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
1944 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
1945 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
1946 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
1947 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
92870c98 1948\r
1949 //\r
1950 // 4.3.3 Device Slot Initialization\r
1951 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
1952 //\r
1847ed0b 1953 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));\r
92870c98 1954 ASSERT (InputContext != NULL);\r
1955 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
a9292c13 1956 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
92870c98 1957\r
a9292c13 1958 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
92870c98 1959\r
1960 //\r
1961 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
1962 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
1963 // Context are affected by the command.\r
1964 //\r
1965 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
1966\r
1967 //\r
1968 // 3) Initialize the Input Slot Context data structure\r
1969 //\r
a9292c13 1970 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
92870c98 1971 InputContext->Slot.Speed = DeviceSpeed + 1;\r
1972 InputContext->Slot.ContextEntries = 1;\r
a9292c13 1973 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
92870c98 1974\r
a9292c13 1975 if (RouteChart.Route.RouteString) {\r
92870c98 1976 //\r
1977 // The device is behind of hub device.\r
1978 //\r
a9292c13 1979 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
92870c98 1980 ASSERT (ParentSlotId != 0);\r
1981 //\r
1982 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
1983 //\r
a9292c13 1984 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
92870c98 1985 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
1986 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
1987 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
1988 //\r
1989 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
1990 // environment from Full/Low speed signaling environment for a device\r
1991 //\r
1992 InputContext->Slot.TTPortNum = ParentPort;\r
1993 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
1994 }\r
1995 } else {\r
1996 //\r
1997 // Inherit the TT parameters from parent device.\r
1998 //\r
1999 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2000 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2001 //\r
2002 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2003 //\r
2004 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2005 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2006 }\r
2007 }\r
2008 }\r
2009\r
2010 //\r
2011 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
2012 //\r
a9292c13 2013 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2014 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2015 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
92870c98 2016 //\r
2017 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2018 //\r
2019 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2020\r
2021 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2022 InputContext->EP[0].MaxPacketSize = 512;\r
2023 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2024 InputContext->EP[0].MaxPacketSize = 64;\r
2025 } else {\r
2026 InputContext->EP[0].MaxPacketSize = 8;\r
2027 }\r
2028 //\r
2029 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2030 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2031 //\r
2032 InputContext->EP[0].AverageTRBLength = 8;\r
2033 InputContext->EP[0].MaxBurstSize = 0;\r
2034 InputContext->EP[0].Interval = 0;\r
2035 InputContext->EP[0].MaxPStreams = 0;\r
2036 InputContext->EP[0].Mult = 0;\r
2037 InputContext->EP[0].CErr = 3;\r
2038\r
2039 //\r
2040 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2041 //\r
1847ed0b
EL
2042 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2043 Xhc->MemPool,\r
2044 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2045 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2046 );\r
2047 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2048 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2049\r
2050 //\r
2051 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2052 //\r
1847ed0b 2053 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));\r
a9292c13 2054 ASSERT (OutputContext != NULL);\r
2055 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2056 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
92870c98 2057\r
a9292c13 2058 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
92870c98 2059 //\r
2060 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2061 // a pointer to the Output Device Context data structure (6.2.1).\r
2062 //\r
1847ed0b
EL
2063 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
2064 //\r
2065 // Fill DCBAA with PCI device address\r
2066 //\r
2067 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
92870c98 2068\r
2069 //\r
2070 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2071 // Context data structure described above.\r
2072 //\r
2073 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1847ed0b
EL
2074 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
2075 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2076 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2077 CmdTrbAddr.CycleBit = 1;\r
2078 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
a9292c13 2079 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2080 Status = XhcCmdTransfer (\r
2081 Xhc,\r
a9292c13 2082 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
92870c98 2083 XHC_GENERIC_TIMEOUT,\r
a9292c13 2084 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2085 );\r
260fbf53
EL
2086 if (!EFI_ERROR (Status)) {\r
2087 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;\r
2088 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2089 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2090 }\r
92870c98 2091\r
2092 return Status;\r
2093}\r
2094\r
2095/**\r
6b4483cd 2096 Assign and initialize the device slot for a new device.\r
92870c98 2097\r
6b4483cd 2098 @param Xhc The XHCI Instance.\r
2099 @param ParentRouteChart The route string pointed to the parent device.\r
2100 @param ParentPort The port at which the device is located.\r
2101 @param RouteChart The route string pointed to the device.\r
2102 @param DeviceSpeed The device speed.\r
92870c98 2103\r
6b4483cd 2104 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
92870c98 2105\r
2106**/\r
2107EFI_STATUS\r
2108EFIAPI\r
6b4483cd 2109XhcInitializeDeviceSlot64 (\r
2110 IN USB_XHCI_INSTANCE *Xhc,\r
2111 IN USB_DEV_ROUTE ParentRouteChart,\r
2112 IN UINT16 ParentPort,\r
2113 IN USB_DEV_ROUTE RouteChart,\r
2114 IN UINT8 DeviceSpeed\r
92870c98 2115 )\r
2116{\r
6b4483cd 2117 EFI_STATUS Status;\r
2118 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2119 INPUT_CONTEXT_64 *InputContext;\r
2120 DEVICE_CONTEXT_64 *OutputContext;\r
2121 TRANSFER_RING *EndpointTransferRing;\r
2122 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2123 UINT8 DeviceAddress;\r
2124 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2125 UINT8 SlotId;\r
2126 UINT8 ParentSlotId;\r
2127 DEVICE_CONTEXT_64 *ParentDeviceContext;\r
1847ed0b 2128 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 2129\r
6b4483cd 2130 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
2131 CmdTrb.CycleBit = 1;\r
2132 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
92870c98 2133\r
6b4483cd 2134 Status = XhcCmdTransfer (\r
2135 Xhc,\r
2136 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
2137 XHC_GENERIC_TIMEOUT,\r
2138 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2139 );\r
260fbf53
EL
2140 if (EFI_ERROR (Status)) {\r
2141 DEBUG ((EFI_D_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
2142 return Status;\r
2143 }\r
6b4483cd 2144 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
2145 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
2146 SlotId = (UINT8)EvtTrb->SlotId;\r
2147 ASSERT (SlotId != 0);\r
92870c98 2148\r
6b4483cd 2149 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2150 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2151 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2152 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2153 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
92870c98 2154\r
2155 //\r
6b4483cd 2156 // 4.3.3 Device Slot Initialization\r
2157 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
92870c98 2158 //\r
1847ed0b 2159 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));\r
6b4483cd 2160 ASSERT (InputContext != NULL);\r
2161 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
2162 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2163\r
2164 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
92870c98 2165\r
92870c98 2166 //\r
6b4483cd 2167 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2168 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2169 // Context are affected by the command.\r
92870c98 2170 //\r
6b4483cd 2171 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
92870c98 2172\r
2173 //\r
6b4483cd 2174 // 3) Initialize the Input Slot Context data structure\r
92870c98 2175 //\r
6b4483cd 2176 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
2177 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2178 InputContext->Slot.ContextEntries = 1;\r
2179 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
92870c98 2180\r
6b4483cd 2181 if (RouteChart.Route.RouteString) {\r
2182 //\r
2183 // The device is behind of hub device.\r
2184 //\r
2185 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
2186 ASSERT (ParentSlotId != 0);\r
2187 //\r
2188 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2189 //\r
2190 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
2191 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2192 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
2193 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2194 //\r
2195 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2196 // environment from Full/Low speed signaling environment for a device\r
2197 //\r
2198 InputContext->Slot.TTPortNum = ParentPort;\r
2199 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2200 }\r
2201 } else {\r
2202 //\r
2203 // Inherit the TT parameters from parent device.\r
2204 //\r
2205 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2206 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2207 //\r
2208 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2209 //\r
2210 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2211 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2212 }\r
92870c98 2213 }\r
2214 }\r
2215\r
92870c98 2216 //\r
6b4483cd 2217 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
92870c98 2218 //\r
6b4483cd 2219 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2220 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2221 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
2222 //\r
2223 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2224 //\r
2225 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2226\r
2227 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2228 InputContext->EP[0].MaxPacketSize = 512;\r
2229 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2230 InputContext->EP[0].MaxPacketSize = 64;\r
2231 } else {\r
2232 InputContext->EP[0].MaxPacketSize = 8;\r
2233 }\r
2234 //\r
2235 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2236 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2237 //\r
2238 InputContext->EP[0].AverageTRBLength = 8;\r
2239 InputContext->EP[0].MaxBurstSize = 0;\r
2240 InputContext->EP[0].Interval = 0;\r
2241 InputContext->EP[0].MaxPStreams = 0;\r
2242 InputContext->EP[0].Mult = 0;\r
2243 InputContext->EP[0].CErr = 3;\r
2244\r
2245 //\r
2246 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2247 //\r
1847ed0b
EL
2248 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2249 Xhc->MemPool,\r
2250 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2251 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2252 );\r
2253 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2254 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2255\r
2256 //\r
2257 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2258 //\r
1847ed0b 2259 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));\r
6b4483cd 2260 ASSERT (OutputContext != NULL);\r
2261 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
2262 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2263\r
2264 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
2265 //\r
2266 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2267 // a pointer to the Output Device Context data structure (6.2.1).\r
2268 //\r
1847ed0b
EL
2269 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2270 //\r
2271 // Fill DCBAA with PCI device address\r
2272 //\r
2273 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) PhyAddr;\r
6b4483cd 2274\r
2275 //\r
2276 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2277 // Context data structure described above.\r
2278 //\r
2279 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
1847ed0b
EL
2280 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
2281 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2282 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2283 CmdTrbAddr.CycleBit = 1;\r
2284 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
2285 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2286 Status = XhcCmdTransfer (\r
2287 Xhc,\r
2288 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
2289 XHC_GENERIC_TIMEOUT,\r
2290 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2291 );\r
260fbf53
EL
2292 if (!EFI_ERROR (Status)) {\r
2293 DeviceAddress = (UINT8) ((DEVICE_CONTEXT_64 *) OutputContext)->Slot.DeviceAddress;\r
2294 DEBUG ((EFI_D_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2295 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2296 }\r
6b4483cd 2297 return Status;\r
2298}\r
2299\r
2300\r
2301/**\r
2302 Disable the specified device slot.\r
2303\r
2304 @param Xhc The XHCI Instance.\r
2305 @param SlotId The slot id to be disabled.\r
2306\r
2307 @retval EFI_SUCCESS Successfully disable the device slot.\r
2308\r
2309**/\r
2310EFI_STATUS\r
2311EFIAPI\r
2312XhcDisableSlotCmd (\r
2313 IN USB_XHCI_INSTANCE *Xhc,\r
2314 IN UINT8 SlotId\r
2315 )\r
2316{\r
2317 EFI_STATUS Status;\r
2318 TRB_TEMPLATE *EvtTrb;\r
2319 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2320 UINT8 Index;\r
2321 VOID *RingSeg;\r
2322\r
2323 //\r
2324 // Disable the device slots occupied by these devices on its downstream ports.\r
2325 // Entry 0 is reserved.\r
2326 //\r
2327 for (Index = 0; Index < 255; Index++) {\r
2328 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2329 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2330 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2331 continue;\r
2332 }\r
2333\r
2334 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2335\r
2336 if (EFI_ERROR (Status)) {\r
2337 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2338 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2339 }\r
2340 }\r
2341\r
2342 //\r
2343 // Construct the disable slot command\r
2344 //\r
2345 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
2346\r
2347 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2348 CmdTrbDisSlot.CycleBit = 1;\r
2349 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2350 CmdTrbDisSlot.SlotId = SlotId;\r
2351 Status = XhcCmdTransfer (\r
2352 Xhc,\r
2353 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2354 XHC_GENERIC_TIMEOUT,\r
2355 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2356 );\r
260fbf53
EL
2357 if (EFI_ERROR (Status)) {\r
2358 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2359 return Status;\r
2360 }\r
6b4483cd 2361 //\r
2362 // Free the slot's device context entry\r
2363 //\r
2364 Xhc->DCBAA[SlotId] = 0;\r
2365\r
2366 //\r
2367 // Free the slot related data structure\r
2368 //\r
2369 for (Index = 0; Index < 31; Index++) {\r
2370 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2371 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2372 if (RingSeg != NULL) {\r
1847ed0b 2373 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
6b4483cd 2374 }\r
2375 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1847ed0b 2376 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
6b4483cd 2377 }\r
2378 }\r
2379\r
2380 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2381 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2382 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2383 }\r
2384 }\r
2385\r
2386 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1847ed0b 2387 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
6b4483cd 2388 }\r
2389\r
2390 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1847ed0b 2391 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
6b4483cd 2392 }\r
2393 //\r
2394 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2395 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2396 // remove urb from XHCI's asynchronous transfer list.\r
2397 //\r
2398 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2399 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2400\r
2401 return Status;\r
2402}\r
2403\r
2404/**\r
2405 Disable the specified device slot.\r
2406\r
2407 @param Xhc The XHCI Instance.\r
2408 @param SlotId The slot id to be disabled.\r
2409\r
2410 @retval EFI_SUCCESS Successfully disable the device slot.\r
2411\r
2412**/\r
2413EFI_STATUS\r
2414EFIAPI\r
2415XhcDisableSlotCmd64 (\r
2416 IN USB_XHCI_INSTANCE *Xhc,\r
2417 IN UINT8 SlotId\r
2418 )\r
2419{\r
2420 EFI_STATUS Status;\r
2421 TRB_TEMPLATE *EvtTrb;\r
2422 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2423 UINT8 Index;\r
2424 VOID *RingSeg;\r
2425\r
2426 //\r
2427 // Disable the device slots occupied by these devices on its downstream ports.\r
2428 // Entry 0 is reserved.\r
2429 //\r
2430 for (Index = 0; Index < 255; Index++) {\r
2431 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2432 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2433 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
2434 continue;\r
2435 }\r
2436\r
2437 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2438\r
2439 if (EFI_ERROR (Status)) {\r
2440 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2441 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2442 }\r
2443 }\r
2444\r
2445 //\r
2446 // Construct the disable slot command\r
2447 //\r
2448 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
2449\r
2450 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2451 CmdTrbDisSlot.CycleBit = 1;\r
2452 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2453 CmdTrbDisSlot.SlotId = SlotId;\r
2454 Status = XhcCmdTransfer (\r
2455 Xhc,\r
2456 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
2457 XHC_GENERIC_TIMEOUT,\r
2458 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2459 );\r
260fbf53
EL
2460 if (EFI_ERROR (Status)) {\r
2461 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2462 return Status;\r
2463 }\r
6b4483cd 2464 //\r
2465 // Free the slot's device context entry\r
2466 //\r
2467 Xhc->DCBAA[SlotId] = 0;\r
2468\r
2469 //\r
2470 // Free the slot related data structure\r
2471 //\r
2472 for (Index = 0; Index < 31; Index++) {\r
2473 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2474 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2475 if (RingSeg != NULL) {\r
1847ed0b 2476 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
6b4483cd 2477 }\r
2478 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
1847ed0b 2479 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
6b4483cd 2480 }\r
2481 }\r
2482\r
2483 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2484 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2485 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2486 }\r
2487 }\r
2488\r
2489 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1847ed0b 2490 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
6b4483cd 2491 }\r
2492\r
2493 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1847ed0b 2494 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
6b4483cd 2495 }\r
2496 //\r
2497 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2498 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2499 // remove urb from XHCI's asynchronous transfer list.\r
2500 //\r
2501 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2502 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2503\r
2504 return Status;\r
2505}\r
2506\r
2507\r
2508/**\r
2509 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
2510\r
2511 @param Xhc The XHCI Instance.\r
2512 @param SlotId The slot id to be configured.\r
2513 @param DeviceSpeed The device's speed.\r
2514 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
2515\r
2516 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
2517\r
2518**/\r
2519EFI_STATUS\r
2520EFIAPI\r
2521XhcSetConfigCmd (\r
2522 IN USB_XHCI_INSTANCE *Xhc,\r
2523 IN UINT8 SlotId,\r
2524 IN UINT8 DeviceSpeed,\r
2525 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
2526 )\r
2527{\r
2528 EFI_STATUS Status;\r
6b4483cd 2529 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
2530 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2531 UINT8 Index;\r
2532 UINTN NumEp;\r
2533 UINTN EpIndex;\r
2534 UINT8 EpAddr;\r
2535 UINT8 Direction;\r
2536 UINT8 Dci;\r
2537 UINT8 MaxDci;\r
1847ed0b 2538 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 2539 UINT8 Interval;\r
2540\r
2541 TRANSFER_RING *EndpointTransferRing;\r
2542 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
2543 INPUT_CONTEXT *InputContext;\r
2544 DEVICE_CONTEXT *OutputContext;\r
2545 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2546 //\r
2547 // 4.6.6 Configure Endpoint\r
2548 //\r
2549 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2550 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
2551 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2552 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
2553\r
2554 ASSERT (ConfigDesc != NULL);\r
2555\r
2556 MaxDci = 0;\r
2557\r
2558 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
2559 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
2560 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {\r
2561 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2562 }\r
2563\r
2564 NumEp = IfDesc->NumEndpoints;\r
2565\r
2566 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2567 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2568 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2569 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2570 }\r
2571\r
2572 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2573 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2574\r
2575 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2576 ASSERT (Dci < 32);\r
2577 if (Dci > MaxDci) {\r
2578 MaxDci = Dci;\r
2579 }\r
2580\r
2581 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2582 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2583\r
2584 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2585 //\r
2586 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2587 //\r
2588 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2589 } else {\r
2590 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2591 }\r
2592\r
2593 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2594 case USB_ENDPOINT_BULK:\r
2595 if (Direction == EfiUsbDataIn) {\r
2596 InputContext->EP[Dci-1].CErr = 3;\r
2597 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2598 } else {\r
2599 InputContext->EP[Dci-1].CErr = 3;\r
2600 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2601 }\r
2602\r
2603 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2604 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2605 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2606 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2607 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2608 }\r
2609\r
2610 break;\r
2611 case USB_ENDPOINT_ISO:\r
2612 if (Direction == EfiUsbDataIn) {\r
2613 InputContext->EP[Dci-1].CErr = 0;\r
2614 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2615 } else {\r
2616 InputContext->EP[Dci-1].CErr = 0;\r
2617 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2618 }\r
2619 break;\r
2620 case USB_ENDPOINT_INTERRUPT:\r
2621 if (Direction == EfiUsbDataIn) {\r
2622 InputContext->EP[Dci-1].CErr = 3;\r
2623 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2624 } else {\r
2625 InputContext->EP[Dci-1].CErr = 3;\r
2626 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2627 }\r
2628 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2629 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2630 //\r
2631 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2632 //\r
2633 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2634 Interval = EpDesc->Interval;\r
2635 //\r
2636 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.\r
2637 //\r
2638 InputContext->EP[Dci-1].Interval = 6;\r
2639 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2640 Interval = EpDesc->Interval;\r
2641 ASSERT (Interval >= 1 && Interval <= 16);\r
2642 //\r
2643 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2644 //\r
2645 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2646 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2647 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2648 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2649 InputContext->EP[Dci-1].CErr = 3;\r
2650 }\r
2651\r
2652 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2653 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2654 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2655 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2656 }\r
2657 break;\r
2658\r
2659 case USB_ENDPOINT_CONTROL:\r
2660 default:\r
2661 ASSERT (0);\r
2662 break;\r
2663 }\r
2664\r
1847ed0b
EL
2665 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2666 Xhc->MemPool,\r
2667 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2668 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2669 );\r
6b4483cd 2670 PhyAddr &= ~(0x0F);\r
2671 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
1847ed0b
EL
2672 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2673 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2674\r
2675 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2676 }\r
2677 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2678 }\r
2679\r
2680 InputContext->InputControlContext.Dword2 |= BIT0;\r
2681 InputContext->Slot.ContextEntries = MaxDci;\r
2682 //\r
2683 // configure endpoint\r
2684 //\r
2685 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
2686 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
2687 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2688 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 2689 CmdTrbCfgEP.CycleBit = 1;\r
2690 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
2691 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2692 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
2693 Status = XhcCmdTransfer (\r
2694 Xhc,\r
2695 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
2696 XHC_GENERIC_TIMEOUT,\r
2697 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
2698 );\r
260fbf53
EL
2699 if (EFI_ERROR (Status)) {\r
2700 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
2701 }\r
92870c98 2702 return Status;\r
2703}\r
2704\r
2705/**\r
2706 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
2707\r
a9292c13 2708 @param Xhc The XHCI Instance.\r
92870c98 2709 @param SlotId The slot id to be configured.\r
2710 @param DeviceSpeed The device's speed.\r
2711 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
2712\r
2713 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
2714\r
2715**/\r
2716EFI_STATUS\r
2717EFIAPI\r
6b4483cd 2718XhcSetConfigCmd64 (\r
a9292c13 2719 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2720 IN UINT8 SlotId,\r
a9292c13 2721 IN UINT8 DeviceSpeed,\r
92870c98 2722 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
2723 )\r
2724{\r
a9292c13 2725 EFI_STATUS Status;\r
a9292c13 2726 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
2727 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2728 UINT8 Index;\r
2729 UINTN NumEp;\r
2730 UINTN EpIndex;\r
2731 UINT8 EpAddr;\r
2732 UINT8 Direction;\r
2733 UINT8 Dci;\r
2734 UINT8 MaxDci;\r
1847ed0b 2735 EFI_PHYSICAL_ADDRESS PhyAddr;\r
a9292c13 2736 UINT8 Interval;\r
2737\r
2738 TRANSFER_RING *EndpointTransferRing;\r
2739 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
6b4483cd 2740 INPUT_CONTEXT_64 *InputContext;\r
2741 DEVICE_CONTEXT_64 *OutputContext;\r
a9292c13 2742 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
92870c98 2743 //\r
2744 // 4.6.6 Configure Endpoint\r
2745 //\r
a9292c13 2746 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2747 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
6b4483cd 2748 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2749 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
92870c98 2750\r
2751 ASSERT (ConfigDesc != NULL);\r
2752\r
2753 MaxDci = 0;\r
2754\r
2755 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
2756 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
2757 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {\r
2758 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2759 }\r
2760\r
2761 NumEp = IfDesc->NumEndpoints;\r
2762\r
2763 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2764 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2765 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2766 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2767 }\r
2768\r
ce9b5900 2769 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
92870c98 2770 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2771\r
2772 Dci = XhcEndpointToDci (EpAddr, Direction);\r
a9292c13 2773 ASSERT (Dci < 32);\r
92870c98 2774 if (Dci > MaxDci) {\r
2775 MaxDci = Dci;\r
2776 }\r
2777\r
2778 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2779 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2780\r
2781 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2782 //\r
2783 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2784 //\r
2785 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2786 } else {\r
2787 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2788 }\r
2789\r
2790 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2791 case USB_ENDPOINT_BULK:\r
2792 if (Direction == EfiUsbDataIn) {\r
2793 InputContext->EP[Dci-1].CErr = 3;\r
2794 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2795 } else {\r
2796 InputContext->EP[Dci-1].CErr = 3;\r
2797 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2798 }\r
2799\r
2800 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
a9292c13 2801 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2802 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2803 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2804 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
92870c98 2805 }\r
2806\r
2807 break;\r
2808 case USB_ENDPOINT_ISO:\r
2809 if (Direction == EfiUsbDataIn) {\r
2810 InputContext->EP[Dci-1].CErr = 0;\r
2811 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2812 } else {\r
2813 InputContext->EP[Dci-1].CErr = 0;\r
2814 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2815 }\r
2816 break;\r
2817 case USB_ENDPOINT_INTERRUPT:\r
2818 if (Direction == EfiUsbDataIn) {\r
2819 InputContext->EP[Dci-1].CErr = 3;\r
2820 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2821 } else {\r
2822 InputContext->EP[Dci-1].CErr = 3;\r
2823 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2824 }\r
2825 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2826 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2827 //\r
2828 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2829 //\r
2830 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2831 Interval = EpDesc->Interval;\r
2832 //\r
a9292c13 2833 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.\r
92870c98 2834 //\r
2835 InputContext->EP[Dci-1].Interval = 6;\r
a9292c13 2836 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
92870c98 2837 Interval = EpDesc->Interval;\r
a9292c13 2838 ASSERT (Interval >= 1 && Interval <= 16);\r
2839 //\r
2840 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2841 //\r
2842 InputContext->EP[Dci-1].Interval = Interval - 1;\r
92870c98 2843 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2844 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2845 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2846 InputContext->EP[Dci-1].CErr = 3;\r
2847 }\r
2848\r
a9292c13 2849 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2850 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2851 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2852 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
92870c98 2853 }\r
2854 break;\r
2855\r
2856 case USB_ENDPOINT_CONTROL:\r
2857 default:\r
2858 ASSERT (0);\r
2859 break;\r
2860 }\r
2861\r
1847ed0b
EL
2862 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2863 Xhc->MemPool,\r
2864 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2865 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2866 );\r
2867\r
92870c98 2868 PhyAddr &= ~(0x0F);\r
a9292c13 2869 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
1847ed0b
EL
2870\r
2871 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2872 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2873\r
2874 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2875 }\r
2876 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2877 }\r
2878\r
2879 InputContext->InputControlContext.Dword2 |= BIT0;\r
2880 InputContext->Slot.ContextEntries = MaxDci;\r
2881 //\r
2882 // configure endpoint\r
2883 //\r
2884 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
2885 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
2886 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2887 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2888 CmdTrbCfgEP.CycleBit = 1;\r
2889 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 2890 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2891 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
2892 Status = XhcCmdTransfer (\r
2893 Xhc,\r
a9292c13 2894 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 2895 XHC_GENERIC_TIMEOUT,\r
a9292c13 2896 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2897 );\r
260fbf53
EL
2898 if (EFI_ERROR (Status)) {\r
2899 DEBUG ((EFI_D_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
2900 }\r
92870c98 2901\r
2902 return Status;\r
2903}\r
2904\r
6b4483cd 2905\r
92870c98 2906/**\r
2907 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
2908\r
a9292c13 2909 @param Xhc The XHCI Instance.\r
92870c98 2910 @param SlotId The slot id to be evaluated.\r
2911 @param MaxPacketSize The max packet size supported by the device control transfer.\r
2912\r
2913 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
2914\r
2915**/\r
2916EFI_STATUS\r
2917EFIAPI\r
2918XhcEvaluateContext (\r
a9292c13 2919 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2920 IN UINT8 SlotId,\r
2921 IN UINT32 MaxPacketSize\r
2922 )\r
2923{\r
a9292c13 2924 EFI_STATUS Status;\r
2925 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
2926 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2927 INPUT_CONTEXT *InputContext;\r
1847ed0b 2928 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 2929\r
a9292c13 2930 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
92870c98 2931\r
2932 //\r
2933 // 4.6.7 Evaluate Context\r
2934 //\r
a9292c13 2935 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
92870c98 2936 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2937\r
2938 InputContext->InputControlContext.Dword2 |= BIT1;\r
2939 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
2940\r
2941 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1847ed0b
EL
2942 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
2943 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2944 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 2945 CmdTrbEvalu.CycleBit = 1;\r
2946 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
a9292c13 2947 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2948 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
2949 Status = XhcCmdTransfer (\r
2950 Xhc,\r
a9292c13 2951 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
92870c98 2952 XHC_GENERIC_TIMEOUT,\r
a9292c13 2953 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2954 );\r
260fbf53
EL
2955 if (EFI_ERROR (Status)) {\r
2956 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
2957 }\r
92870c98 2958 return Status;\r
2959}\r
2960\r
6b4483cd 2961/**\r
2962 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
2963\r
2964 @param Xhc The XHCI Instance.\r
2965 @param SlotId The slot id to be evaluated.\r
2966 @param MaxPacketSize The max packet size supported by the device control transfer.\r
2967\r
2968 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
2969\r
2970**/\r
2971EFI_STATUS\r
2972EFIAPI\r
2973XhcEvaluateContext64 (\r
2974 IN USB_XHCI_INSTANCE *Xhc,\r
2975 IN UINT8 SlotId,\r
2976 IN UINT32 MaxPacketSize\r
2977 )\r
2978{\r
2979 EFI_STATUS Status;\r
2980 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
2981 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2982 INPUT_CONTEXT_64 *InputContext;\r
1847ed0b 2983 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 2984\r
2985 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2986\r
2987 //\r
2988 // 4.6.7 Evaluate Context\r
2989 //\r
2990 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2991 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2992\r
2993 InputContext->InputControlContext.Dword2 |= BIT1;\r
2994 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
2995\r
2996 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
1847ed0b
EL
2997 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
2998 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2999 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 3000 CmdTrbEvalu.CycleBit = 1;\r
3001 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
3002 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3003 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
3004 Status = XhcCmdTransfer (\r
3005 Xhc,\r
3006 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
3007 XHC_GENERIC_TIMEOUT,\r
3008 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3009 );\r
260fbf53
EL
3010 if (EFI_ERROR (Status)) {\r
3011 DEBUG ((EFI_D_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
3012 }\r
6b4483cd 3013 return Status;\r
3014}\r
3015\r
3016\r
92870c98 3017/**\r
3018 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
3019\r
a9292c13 3020 @param Xhc The XHCI Instance.\r
92870c98 3021 @param SlotId The slot id to be configured.\r
3022 @param PortNum The total number of downstream port supported by the hub.\r
3023 @param TTT The TT think time of the hub device.\r
3024 @param MTT The multi-TT of the hub device.\r
3025\r
3026 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
3027\r
3028**/\r
3029EFI_STATUS\r
3030XhcConfigHubContext (\r
a9292c13 3031 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 3032 IN UINT8 SlotId,\r
3033 IN UINT8 PortNum,\r
3034 IN UINT8 TTT,\r
3035 IN UINT8 MTT\r
3036 )\r
3037{\r
a9292c13 3038 EFI_STATUS Status;\r
a9292c13 3039 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3040 INPUT_CONTEXT *InputContext;\r
3041 DEVICE_CONTEXT *OutputContext;\r
3042 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1847ed0b 3043 EFI_PHYSICAL_ADDRESS PhyAddr;\r
92870c98 3044\r
a9292c13 3045 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3046 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3047 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
92870c98 3048\r
3049 //\r
3050 // 4.6.7 Evaluate Context\r
3051 //\r
3052 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3053\r
3054 InputContext->InputControlContext.Dword2 |= BIT0;\r
3055\r
3056 //\r
3057 // Copy the slot context from OutputContext to Input context\r
3058 //\r
a9292c13 3059 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
92870c98 3060 InputContext->Slot.Hub = 1;\r
3061 InputContext->Slot.PortNum = PortNum;\r
3062 InputContext->Slot.TTT = TTT;\r
3063 InputContext->Slot.MTT = MTT;\r
3064\r
3065 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3066 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3067 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3068 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
92870c98 3069 CmdTrbCfgEP.CycleBit = 1;\r
3070 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 3071 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 3072 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
3073 Status = XhcCmdTransfer (\r
3074 Xhc,\r
a9292c13 3075 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 3076 XHC_GENERIC_TIMEOUT,\r
a9292c13 3077 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 3078 );\r
260fbf53
EL
3079 if (EFI_ERROR (Status)) {\r
3080 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
3081 }\r
92870c98 3082 return Status;\r
3083}\r
3084\r
6b4483cd 3085/**\r
3086 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
3087\r
3088 @param Xhc The XHCI Instance.\r
3089 @param SlotId The slot id to be configured.\r
3090 @param PortNum The total number of downstream port supported by the hub.\r
3091 @param TTT The TT think time of the hub device.\r
3092 @param MTT The multi-TT of the hub device.\r
3093\r
3094 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
3095\r
3096**/\r
3097EFI_STATUS\r
3098XhcConfigHubContext64 (\r
3099 IN USB_XHCI_INSTANCE *Xhc,\r
3100 IN UINT8 SlotId,\r
3101 IN UINT8 PortNum,\r
3102 IN UINT8 TTT,\r
3103 IN UINT8 MTT\r
3104 )\r
3105{\r
3106 EFI_STATUS Status;\r
6b4483cd 3107 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3108 INPUT_CONTEXT_64 *InputContext;\r
3109 DEVICE_CONTEXT_64 *OutputContext;\r
3110 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1847ed0b 3111 EFI_PHYSICAL_ADDRESS PhyAddr;\r
6b4483cd 3112\r
3113 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3114 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3115 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3116\r
3117 //\r
3118 // 4.6.7 Evaluate Context\r
3119 //\r
3120 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3121\r
3122 InputContext->InputControlContext.Dword2 |= BIT0;\r
3123\r
3124 //\r
3125 // Copy the slot context from OutputContext to Input context\r
3126 //\r
3127 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
3128 InputContext->Slot.Hub = 1;\r
3129 InputContext->Slot.PortNum = PortNum;\r
3130 InputContext->Slot.TTT = TTT;\r
3131 InputContext->Slot.MTT = MTT;\r
3132\r
3133 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
1847ed0b
EL
3134 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3135 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3136 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
6b4483cd 3137 CmdTrbCfgEP.CycleBit = 1;\r
3138 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3139 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3140 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
3141 Status = XhcCmdTransfer (\r
3142 Xhc,\r
3143 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
3144 XHC_GENERIC_TIMEOUT,\r
3145 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
3146 );\r
260fbf53
EL
3147 if (EFI_ERROR (Status)) {\r
3148 DEBUG ((EFI_D_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
3149 }\r
6b4483cd 3150 return Status;\r
3151}\r
3152\r
3153\r