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