]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
Fix CrytoPkg issue in GCC X64 tip.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
CommitLineData
92870c98 1/** @file\r
2\r
3 XHCI transfer scheduling routines.\r
4\r
5Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
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
50 Urb->EvtRing = &Xhc->CmdEventRing;\r
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
109 ASSERT (Urb->EvtRing == &Xhc->CmdEventRing);\r
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
92870c98 128 @param DevAddr The device address\r
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
92870c98 145 IN UINT8 DevAddr,\r
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
170 Ep->DevAddr = DevAddr;\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
a9292c13 204 DEVICE_CONTEXT *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
a9292c13 214 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
ce9b5900 215 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
a9292c13 216 ASSERT (Dci < 32);\r
217 EPRing = (TRANSFER_RING *)(UINTN) Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
92870c98 218 Urb->Ring = EPRing;\r
a9292c13 219 OutputContext = (DEVICE_CONTEXT *)(UINTN) Xhc->DCBAA[SlotId];\r
220 EPType = (UINT8) OutputContext->EP[Dci-1].EPType;\r
92870c98 221\r
222 //\r
223 // Construct the TRB\r
224 //\r
225 XhcSyncTrsRing (Xhc, EPRing);\r
226 Urb->TrbStart = EPRing->RingEnqueue;\r
227 switch (EPType) {\r
228 case ED_CONTROL_BIDIR:\r
229 Urb->EvtRing = &Xhc->CtrlTrEventRing;\r
230 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
231 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
232 //\r
233 // For control transfer, create SETUP_STAGE_TRB first.\r
234 //\r
a9292c13 235 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
236 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
237 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;\r
238 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
239 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
240 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
241 TrbStart->TrbCtrSetup.Lenth = 8;\r
242 TrbStart->TrbCtrSetup.IntTarget = Urb->EvtRing->EventInterrupter;\r
243 TrbStart->TrbCtrSetup.IOC = 1;\r
244 TrbStart->TrbCtrSetup.IDT = 1;\r
245 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;\r
92870c98 246 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
a9292c13 247 TrbStart->TrbCtrSetup.TRT = 3;\r
92870c98 248 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
a9292c13 249 TrbStart->TrbCtrSetup.TRT = 2;\r
92870c98 250 } else {\r
a9292c13 251 TrbStart->TrbCtrSetup.TRT = 0;\r
92870c98 252 }\r
253 //\r
254 // Update the cycle bit\r
255 //\r
a9292c13 256 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 257 Urb->TrbNum++;\r
258\r
259 //\r
260 // For control transfer, create DATA_STAGE_TRB.\r
261 //\r
262 if (Urb->DataLen > 0) {\r
263 XhcSyncTrsRing (Xhc, EPRing);\r
a9292c13 264 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
265 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->Data);\r
266 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->Data);\r
267 TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen;\r
268 TrbStart->TrbCtrData.TDSize = 0;\r
269 TrbStart->TrbCtrData.IntTarget = Urb->EvtRing->EventInterrupter;\r
270 TrbStart->TrbCtrData.ISP = 1;\r
271 TrbStart->TrbCtrData.IOC = 1;\r
272 TrbStart->TrbCtrData.IDT = 0;\r
273 TrbStart->TrbCtrData.CH = 0;\r
274 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;\r
92870c98 275 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
a9292c13 276 TrbStart->TrbCtrData.DIR = 1;\r
92870c98 277 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
a9292c13 278 TrbStart->TrbCtrData.DIR = 0;\r
92870c98 279 } else {\r
a9292c13 280 TrbStart->TrbCtrData.DIR = 0;\r
92870c98 281 }\r
282 //\r
283 // Update the cycle bit\r
284 //\r
a9292c13 285 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 286 Urb->TrbNum++;\r
287 }\r
288 //\r
289 // For control transfer, create STATUS_STAGE_TRB.\r
290 // Get the pointer to next TRB for status stage use\r
291 //\r
292 XhcSyncTrsRing (Xhc, EPRing);\r
a9292c13 293 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
294 TrbStart->TrbCtrStatus.IntTarget = Urb->EvtRing->EventInterrupter;\r
295 TrbStart->TrbCtrStatus.IOC = 1;\r
296 TrbStart->TrbCtrStatus.CH = 0;\r
297 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;\r
92870c98 298 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
a9292c13 299 TrbStart->TrbCtrStatus.DIR = 0;\r
92870c98 300 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
a9292c13 301 TrbStart->TrbCtrStatus.DIR = 1;\r
92870c98 302 } else {\r
a9292c13 303 TrbStart->TrbCtrStatus.DIR = 0;\r
92870c98 304 }\r
305 //\r
306 // Update the cycle bit\r
307 //\r
a9292c13 308 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 309 //\r
310 // Update the enqueue pointer\r
311 //\r
312 XhcSyncTrsRing (Xhc, EPRing);\r
313 Urb->TrbNum++;\r
a9292c13 314 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
92870c98 315\r
316 break;\r
317\r
318 case ED_BULK_OUT:\r
319 case ED_BULK_IN:\r
320 Urb->EvtRing = &Xhc->BulkTrEventRing;\r
321 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
322 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
323\r
324 TotalLen = 0;\r
325 Len = 0;\r
326 TrbNum = 0;\r
a9292c13 327 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
92870c98 328 while (TotalLen < Urb->DataLen) {\r
329 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
330 Len = Urb->DataLen - TotalLen;\r
331 } else {\r
332 Len = 0x10000;\r
333 }\r
a9292c13 334 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
335 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);\r
336 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);\r
337 TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
338 TrbStart->TrbNormal.TDSize = 0;\r
339 TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter;\r
340 TrbStart->TrbNormal.ISP = 1;\r
341 TrbStart->TrbNormal.IOC = 1;\r
342 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
92870c98 343 //\r
344 // Update the cycle bit\r
345 //\r
a9292c13 346 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 347\r
348 XhcSyncTrsRing (Xhc, EPRing);\r
349 TrbNum++;\r
350 TotalLen += Len;\r
351 }\r
352\r
353 Urb->TrbNum = TrbNum;\r
a9292c13 354 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
92870c98 355 break;\r
356\r
357 case ED_INTERRUPT_OUT:\r
358 case ED_INTERRUPT_IN:\r
359 if (Urb->Ep.Type == XHC_INT_TRANSFER_ASYNC) {\r
360 Urb->EvtRing = &Xhc->AsynIntTrEventRing;\r
361 } else if(Urb->Ep.Type == XHC_INT_TRANSFER_SYNC){\r
362 Urb->EvtRing = &Xhc->IntTrEventRing;\r
363 } else {\r
364 DEBUG ((EFI_D_ERROR, "EP Interrupt type error!\n"));\r
365 ASSERT(FALSE);\r
366 }\r
367 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
368 Urb->EvtTrbStart = Urb->EvtRing->EventRingEnqueue;\r
369\r
370 TotalLen = 0;\r
371 Len = 0;\r
372 TrbNum = 0;\r
a9292c13 373 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
92870c98 374 while (TotalLen < Urb->DataLen) {\r
375 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
376 Len = Urb->DataLen - TotalLen;\r
377 } else {\r
378 Len = 0x10000;\r
379 }\r
a9292c13 380 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
381 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->Data + TotalLen);\r
382 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->Data + TotalLen);\r
383 TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
384 TrbStart->TrbNormal.TDSize = 0;\r
385 TrbStart->TrbNormal.IntTarget = Urb->EvtRing->EventInterrupter;\r
386 TrbStart->TrbNormal.ISP = 1;\r
387 TrbStart->TrbNormal.IOC = 1;\r
388 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
92870c98 389 //\r
390 // Update the cycle bit\r
391 //\r
a9292c13 392 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
92870c98 393\r
394 XhcSyncTrsRing (Xhc, EPRing);\r
395 TrbNum++;\r
396 TotalLen += Len;\r
397 }\r
398\r
399 Urb->TrbNum = TrbNum;\r
a9292c13 400 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
92870c98 401 break;\r
402\r
403 default:\r
404 DEBUG ((EFI_D_INFO, "Not supported EPType 0x%x!\n",EPType));\r
405 ASSERT (FALSE);\r
406 break;\r
407 }\r
408\r
409 return EFI_SUCCESS;\r
410}\r
411\r
412\r
413/**\r
414 Initialize the XHCI host controller for schedule.\r
415\r
a9292c13 416 @param Xhc The XHCI Instance to be initialized.\r
92870c98 417\r
418**/\r
419VOID\r
420XhcInitSched (\r
a9292c13 421 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 422 )\r
423{\r
424 VOID *Dcbaa;\r
425 UINT64 CmdRing;\r
426 UINTN Entries;\r
427 UINT32 MaxScratchpadBufs;\r
428 UINT64 *ScratchBuf;\r
429 UINT64 *ScratchEntryBuf;\r
430 UINT32 Index;\r
431\r
432 //\r
433 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
434 // to enable the device slots that system software is going to use.\r
435 //\r
436 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
437 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
438 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);\r
439\r
440 //\r
441 // The Device Context Base Address Array entry associated with each allocated Device Slot\r
442 // shall contain a 64-bit pointer to the base of the associated Device Context.\r
443 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
444 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
445 //\r
446 Entries = (Xhc->MaxSlotsEn + 1) * sizeof(UINT64);\r
a9292c13 447 Dcbaa = AllocatePages (EFI_SIZE_TO_PAGES (Entries));\r
92870c98 448 ASSERT (Dcbaa != NULL);\r
a9292c13 449 ZeroMem (Dcbaa, Entries);\r
92870c98 450\r
451 //\r
452 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
453 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
454 // mode (Run/Stop(R/S) ='1').\r
455 //\r
456 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
457 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
ce9b5900 458 ASSERT (MaxScratchpadBufs <= 1023);\r
92870c98 459 if (MaxScratchpadBufs != 0) {\r
a9292c13 460 ScratchBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)), Xhc->PageSize);\r
92870c98 461 ASSERT (ScratchBuf != NULL);\r
a9292c13 462 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
92870c98 463 Xhc->ScratchBuf = ScratchBuf;\r
464\r
465 for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
a9292c13 466 ScratchEntryBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (Xhc->PageSize), Xhc->PageSize);\r
467 ASSERT (ScratchEntryBuf != NULL);\r
468 ZeroMem (ScratchEntryBuf, Xhc->PageSize);\r
92870c98 469 *ScratchBuf++ = (UINT64)(UINTN)ScratchEntryBuf;\r
470 }\r
471\r
472 //\r
473 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
474 // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
475 //\r
476 *(UINT64 *)Dcbaa = (UINT64)(UINTN)Xhc->ScratchBuf;\r
477 }\r
478\r
479 //\r
480 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
481 // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
482 //\r
a9292c13 483 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;\r
ce9b5900 484 XhcWriteOpReg64 (Xhc, XHC_DCBAAP_OFFSET, (UINT64)(UINTN)Xhc->DCBAA);\r
485 DEBUG ((EFI_D_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));\r
92870c98 486\r
487 //\r
488 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
489 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
490 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
491 // always be '0'.\r
492 //\r
493 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
494 //\r
495 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
496 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
497 // So we set RCS as inverted PCS init value to let Command Ring empty\r
498 //\r
499 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;\r
500 ASSERT ((CmdRing & 0x3F) == 0);\r
501 CmdRing |= XHC_CRCR_RCS;\r
502 XhcWriteOpReg64 (Xhc, XHC_CRCR_OFFSET, CmdRing);\r
503\r
504 DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
505\r
506 //\r
507 // Disable the 'interrupter enable' bit in USB_CMD\r
508 // and clear IE & IP bit in all Interrupter X Management Registers.\r
509 //\r
510 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
511 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
512 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
513 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
514 }\r
515\r
516 //\r
517 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
518 //\r
519 CreateEventRing (Xhc, CMD_INTER, &Xhc->CmdEventRing);\r
520 CreateEventRing (Xhc, CTRL_INTER, &Xhc->CtrlTrEventRing);\r
521 CreateEventRing (Xhc, BULK_INTER, &Xhc->BulkTrEventRing);\r
a9292c13 522 CreateEventRing (Xhc, INT_INTER, &Xhc->IntTrEventRing);\r
523 CreateEventRing (Xhc, INT_INTER_ASYNC, &Xhc->AsynIntTrEventRing);\r
92870c98 524}\r
525\r
526/**\r
527 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
528 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
529 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
530 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
531 Stopped to the Running state.\r
532\r
a9292c13 533 @param Xhc The XHCI Instance.\r
92870c98 534 @param Urb The urb which makes the endpoint halted.\r
535\r
536 @retval EFI_SUCCESS The recovery is successful.\r
537 @retval Others Failed to recovery halted endpoint.\r
538\r
539**/\r
540EFI_STATUS\r
541EFIAPI\r
542XhcRecoverHaltedEndpoint (\r
a9292c13 543 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 544 IN URB *Urb\r
545 )\r
546{\r
a9292c13 547 EFI_STATUS Status;\r
548 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
549 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
550 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
551 UINT8 Dci;\r
552 UINT8 SlotId;\r
92870c98 553\r
554 Status = EFI_SUCCESS;\r
a9292c13 555 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
ce9b5900 556 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
92870c98 557\r
558 DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
559\r
560 //\r
561 // 1) Send Reset endpoint command to transit from halt to stop state\r
562 //\r
563 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
564 CmdTrbResetED.CycleBit = 1;\r
565 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
566 CmdTrbResetED.EDID = Dci;\r
567 CmdTrbResetED.SlotId = SlotId;\r
568 Status = XhcCmdTransfer (\r
569 Xhc,\r
a9292c13 570 (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
92870c98 571 XHC_GENERIC_TIMEOUT,\r
a9292c13 572 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 573 );\r
574 ASSERT (!EFI_ERROR(Status));\r
575\r
576 //\r
577 // 2)Set dequeue pointer\r
578 //\r
579 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
580 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (Urb->Ring->RingEnqueue) | Urb->Ring->RingPCS;\r
581 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (Urb->Ring->RingEnqueue);\r
582 CmdSetTRDeq.CycleBit = 1;\r
583 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
584 CmdSetTRDeq.Endpoint = Dci;\r
585 CmdSetTRDeq.SlotId = SlotId;\r
586 Status = XhcCmdTransfer (\r
587 Xhc,\r
a9292c13 588 (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
92870c98 589 XHC_GENERIC_TIMEOUT,\r
a9292c13 590 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 591 );\r
592 ASSERT (!EFI_ERROR(Status));\r
593\r
594 //\r
595 // 3)Ring the doorbell to transit from stop to active\r
596 //\r
597 XhcRingDoorBell (Xhc, SlotId, Dci);\r
598\r
599 return Status;\r
600}\r
601\r
602/**\r
603 Create XHCI event ring.\r
604\r
a9292c13 605 @param Xhc The XHCI Instance.\r
92870c98 606 @param EventInterrupter The interrupter of event.\r
607 @param EventRing The created event ring.\r
608\r
609**/\r
610VOID\r
92870c98 611CreateEventRing (\r
a9292c13 612 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 613 IN UINT8 EventInterrupter,\r
614 OUT EVENT_RING *EventRing\r
615 )\r
616{\r
617 VOID *Buf;\r
618 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
619\r
620 ASSERT (EventRing != NULL);\r
621\r
a9292c13 622 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));\r
92870c98 623 ASSERT (Buf != NULL);\r
624 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
a9292c13 625 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
92870c98 626\r
627 EventRing->EventRingSeg0 = Buf;\r
628 EventRing->EventInterrupter = EventInterrupter;\r
629 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
a9292c13 630 EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
631 EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
92870c98 632 //\r
633 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
634 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
635 //\r
636 EventRing->EventRingCCS = 1;\r
637\r
a9292c13 638 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));\r
92870c98 639 ASSERT (Buf != NULL);\r
640 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
a9292c13 641 ZeroMem (Buf, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
92870c98 642\r
643 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *) Buf;\r
644 EventRing->ERSTBase = ERSTBase;\r
645 ERSTBase->PtrLo = XHC_LOW_32BIT (EventRing->EventRingSeg0);\r
646 ERSTBase->PtrHi = XHC_HIGH_32BIT (EventRing->EventRingSeg0);\r
647 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
648\r
649 //\r
650 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
651 //\r
652 XhcWriteRuntimeReg (\r
653 Xhc,\r
654 XHC_ERSTSZ_OFFSET + (32 * EventRing->EventInterrupter),\r
655 ERST_NUMBER\r
656 );\r
657 //\r
658 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
659 //\r
660 XhcWriteRuntimeReg64 (\r
661 Xhc,\r
662 XHC_ERDP_OFFSET + (32 * EventRing->EventInterrupter),\r
ce9b5900 663 (UINT64)(UINTN)EventRing->EventRingDequeue\r
92870c98 664 );\r
665 //\r
666 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)\r
667 //\r
668 XhcWriteRuntimeReg64 (\r
669 Xhc,\r
670 XHC_ERSTBA_OFFSET + (32 * EventRing->EventInterrupter),\r
ce9b5900 671 (UINT64)(UINTN)ERSTBase\r
92870c98 672 );\r
673 //\r
674 // Need set IMAN IE bit to enble the ring interrupt\r
675 //\r
676 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (32 * EventRing->EventInterrupter), XHC_IMAN_IE);\r
677}\r
678\r
679/**\r
680 Create XHCI transfer ring.\r
681\r
a9292c13 682 @param Xhc The XHCI Instance.\r
92870c98 683 @param TrbNum The number of TRB in the ring.\r
684 @param TransferRing The created transfer ring.\r
685\r
686**/\r
687VOID\r
92870c98 688CreateTransferRing (\r
a9292c13 689 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 690 IN UINTN TrbNum,\r
691 OUT TRANSFER_RING *TransferRing\r
692 )\r
693{\r
694 VOID *Buf;\r
a9292c13 695 LINK_TRB *EndTrb;\r
92870c98 696\r
a9292c13 697 Buf = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TrbNum));\r
92870c98 698 ASSERT (Buf != NULL);\r
699 ASSERT (((UINTN) Buf & 0x3F) == 0);\r
a9292c13 700 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
92870c98 701\r
702 TransferRing->RingSeg0 = Buf;\r
703 TransferRing->TrbNumber = TrbNum;\r
a9292c13 704 TransferRing->RingEnqueue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
705 TransferRing->RingDequeue = (TRB_TEMPLATE *) TransferRing->RingSeg0;\r
92870c98 706 TransferRing->RingPCS = 1;\r
707 //\r
708 // 4.9.2 Transfer Ring Management\r
709 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
710 // point to the first TRB in the ring.\r
711 //\r
a9292c13 712 EndTrb = (LINK_TRB *) ((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
92870c98 713 EndTrb->Type = TRB_TYPE_LINK;\r
714 EndTrb->PtrLo = XHC_LOW_32BIT (Buf);\r
715 EndTrb->PtrHi = XHC_HIGH_32BIT (Buf);\r
716 //\r
717 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
718 //\r
719 EndTrb->TC = 1;\r
720 //\r
721 // Set Cycle bit as other TRB PCS init value\r
722 //\r
723 EndTrb->CycleBit = 0;\r
724}\r
725\r
726/**\r
727 Free XHCI event ring.\r
728\r
a9292c13 729 @param Xhc The XHCI Instance.\r
92870c98 730 @param EventRing The event ring to be freed.\r
731\r
732**/\r
733EFI_STATUS\r
734EFIAPI\r
735XhcFreeEventRing (\r
a9292c13 736 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 737 IN EVENT_RING *EventRing\r
738)\r
739{\r
740 UINT8 Index;\r
741 EVENT_RING_SEG_TABLE_ENTRY *TablePtr;\r
742 VOID *RingBuf;\r
743 EVENT_RING_SEG_TABLE_ENTRY *EventRingPtr;\r
92870c98 744\r
745 if(EventRing->EventRingSeg0 == NULL) {\r
746 return EFI_SUCCESS;\r
747 }\r
748\r
92870c98 749 //\r
750 // Get the Event Ring Segment Table base address\r
751 //\r
752 TablePtr = (EVENT_RING_SEG_TABLE_ENTRY *)(EventRing->ERSTBase);\r
753\r
754 //\r
755 // Get all the TRBs Ring and release\r
756 //\r
757 for (Index = 0; Index < ERST_NUMBER; Index++) {\r
758 EventRingPtr = TablePtr + Index;\r
759 RingBuf = (VOID *)(UINTN)(EventRingPtr->PtrLo | ((UINT64)EventRingPtr->PtrHi << 32));\r
760\r
761 if(RingBuf != NULL) {\r
a9292c13 762 FreePages (RingBuf, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER));\r
92870c98 763 ZeroMem (EventRingPtr, sizeof (EVENT_RING_SEG_TABLE_ENTRY));\r
764 }\r
765 }\r
766\r
a9292c13 767 FreePages (TablePtr, EFI_SIZE_TO_PAGES (sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER));\r
92870c98 768 return EFI_SUCCESS;\r
769}\r
770\r
771/**\r
772 Free the resouce allocated at initializing schedule.\r
773\r
a9292c13 774 @param Xhc The XHCI Instance.\r
92870c98 775\r
776**/\r
777VOID\r
778XhcFreeSched (\r
a9292c13 779 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 780 )\r
781{\r
782 UINT32 Index;\r
a9292c13 783 UINT64 *ScratchBuf;\r
92870c98 784\r
785 if (Xhc->ScratchBuf != NULL) {\r
a9292c13 786 ScratchBuf = Xhc->ScratchBuf;\r
92870c98 787 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
a9292c13 788 FreeAlignedPages ((VOID*)(UINTN)*ScratchBuf++, EFI_SIZE_TO_PAGES (Xhc->PageSize));\r
92870c98 789 }\r
a9292c13 790 FreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));\r
92870c98 791 }\r
792\r
793 if (Xhc->DCBAA != NULL) {\r
a9292c13 794 FreePages (Xhc->DCBAA, EFI_SIZE_TO_PAGES((Xhc->MaxSlotsEn + 1) * sizeof(UINT64)));\r
92870c98 795 Xhc->DCBAA = NULL;\r
796 }\r
797\r
798 if (Xhc->CmdRing.RingSeg0 != NULL){\r
a9292c13 799 FreePages (Xhc->CmdRing.RingSeg0, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER));\r
92870c98 800 Xhc->CmdRing.RingSeg0 = NULL;\r
801 }\r
a9292c13 802\r
92870c98 803 XhcFreeEventRing (Xhc,&Xhc->CmdEventRing);\r
804 XhcFreeEventRing (Xhc,&Xhc->CtrlTrEventRing);\r
805 XhcFreeEventRing (Xhc,&Xhc->BulkTrEventRing);\r
806 XhcFreeEventRing (Xhc,&Xhc->AsynIntTrEventRing);\r
807 XhcFreeEventRing (Xhc,&Xhc->IntTrEventRing);\r
808}\r
809\r
810/**\r
811 Check if it is ring TRB.\r
812\r
813 @param Ring The transfer ring\r
814 @param Trb The TRB to check if it's in the transfer ring\r
815\r
816 @retval TRUE It is in the ring\r
817 @retval FALSE It is not in the ring\r
818\r
819**/\r
820BOOLEAN\r
821IsTransferRingTrb (\r
822 IN TRANSFER_RING *Ring,\r
a9292c13 823 IN TRB_TEMPLATE *Trb\r
92870c98 824 )\r
825{\r
826 BOOLEAN Flag;\r
a9292c13 827 TRB_TEMPLATE *Trb1;\r
92870c98 828 UINTN Index;\r
829\r
830 Trb1 = Ring->RingSeg0;\r
831 Flag = FALSE;\r
832\r
833 ASSERT (Ring->TrbNumber == CMD_RING_TRB_NUMBER || Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
834\r
835 for (Index = 0; Index < Ring->TrbNumber; Index++) {\r
836 if (Trb == Trb1) {\r
837 Flag = TRUE;\r
838 break;\r
839 }\r
840 Trb1++;\r
841 }\r
842\r
843 return Flag;\r
844}\r
845\r
846/**\r
847 Check the URB's execution result and update the URB's\r
848 result accordingly.\r
849\r
a9292c13 850 @param Xhc The XHCI Instance.\r
92870c98 851 @param Urb The URB to check result.\r
852\r
853 @return Whether the result of URB transfer is finialized.\r
854\r
855**/\r
856EFI_STATUS\r
857XhcCheckUrbResult (\r
a9292c13 858 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 859 IN URB *Urb\r
860 )\r
861{\r
862 BOOLEAN StartDone;\r
863 BOOLEAN EndDone;\r
864 EVT_TRB_TRANSFER *EvtTrb;\r
a9292c13 865 TRB_TEMPLATE *TRBPtr;\r
92870c98 866 UINTN Index;\r
867 UINT8 TRBType;\r
868 EFI_STATUS Status;\r
869\r
870 ASSERT ((Xhc != NULL) && (Urb != NULL));\r
871\r
872 Urb->Completed = 0;\r
873 Urb->Result = EFI_USB_NOERROR;\r
874 Status = EFI_SUCCESS;\r
875 EvtTrb = NULL;\r
876\r
877 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
878 Urb->Result |= EFI_USB_ERR_SYSTEM;\r
879 Status = EFI_DEVICE_ERROR;\r
880 goto EXIT;\r
881 }\r
882\r
883 //\r
884 // Restore the EventRingDequeue and poll the transfer event ring from beginning\r
885 //\r
886 StartDone = FALSE;\r
887 EndDone = FALSE;\r
888 Urb->EvtRing->EventRingDequeue = Urb->EvtTrbStart;\r
889 for (Index = 0; Index < Urb->EvtRing->TrbNumber; Index++) {\r
890 XhcSyncEventRing (Xhc, Urb->EvtRing);\r
a9292c13 891 Status = XhcCheckNewEvent (Xhc, Urb->EvtRing, ((TRB_TEMPLATE **)&EvtTrb));\r
92870c98 892 if (Status == EFI_NOT_READY) {\r
893 Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
894 goto EXIT;\r
895 }\r
896\r
a9292c13 897 TRBPtr = (TRB_TEMPLATE *)(UINTN)(EvtTrb->TRBPtrLo | (UINT64) EvtTrb->TRBPtrHi << 32);\r
92870c98 898\r
a9292c13 899 switch (EvtTrb->Completecode) {\r
92870c98 900 case TRB_COMPLETION_STALL_ERROR:\r
901 Urb->Result |= EFI_USB_ERR_STALL;\r
902 Status = EFI_DEVICE_ERROR;\r
a9292c13 903 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
92870c98 904 goto EXIT;\r
905 break;\r
906\r
907 case TRB_COMPLETION_BABBLE_ERROR:\r
908 Urb->Result |= EFI_USB_ERR_BABBLE;\r
909 Status = EFI_DEVICE_ERROR;\r
a9292c13 910 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
92870c98 911 goto EXIT;\r
912 break;\r
913\r
914 case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
915 Urb->Result |= EFI_USB_ERR_BUFFER;\r
916 Status = EFI_DEVICE_ERROR;\r
a9292c13 917 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n",EvtTrb->Completecode));\r
92870c98 918 goto EXIT;\r
919 break;\r
920\r
921 case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
922 Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
923 Status = EFI_DEVICE_ERROR;\r
a9292c13 924 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
92870c98 925 goto EXIT;\r
926 break;\r
927\r
928 case TRB_COMPLETION_SHORT_PACKET:\r
929 case TRB_COMPLETION_SUCCESS:\r
930 if (IsTransferRingTrb (Urb->Ring, TRBPtr)) {\r
a9292c13 931 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
92870c98 932 DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));\r
933 }\r
934 TRBType = (UINT8) (TRBPtr->Type);\r
935 if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
936 (TRBType == TRB_TYPE_NORMAL) ||\r
937 (TRBType == TRB_TYPE_ISOCH)) {\r
938 Urb->Completed += (Urb->DataLen - EvtTrb->Lenth);\r
939 }\r
940 }\r
941 Status = EFI_SUCCESS;\r
942 break;\r
943\r
944 default:\r
a9292c13 945 DEBUG ((EFI_D_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n",EvtTrb->Completecode));\r
92870c98 946 Urb->Result |= EFI_USB_ERR_TIMEOUT;\r
947 Status = EFI_DEVICE_ERROR;\r
948 goto EXIT;\r
949 break;\r
950 }\r
951\r
952 //\r
953 // Only check first and end Trb event address\r
954 //\r
955 if (TRBPtr == Urb->TrbStart) {\r
956 StartDone = TRUE;\r
957 }\r
958\r
959 if (TRBPtr == Urb->TrbEnd) {\r
960 EndDone = TRUE;\r
961 }\r
962\r
963 if (StartDone && EndDone) {\r
964 break;\r
965 }\r
966 }\r
967\r
968EXIT:\r
969 return Status;\r
970}\r
971\r
972\r
973/**\r
974 Execute the transfer by polling the URB. This is a synchronous operation.\r
975\r
a9292c13 976 @param Xhc The XHCI Instance.\r
92870c98 977 @param CmdTransfer The executed URB is for cmd transfer or not.\r
978 @param Urb The URB to execute.\r
a9292c13 979 @param Timeout The time to wait before abort, in millisecond.\r
92870c98 980\r
981 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
982 @return EFI_TIMEOUT The transfer failed due to time out.\r
983 @return EFI_SUCCESS The transfer finished OK.\r
984\r
985**/\r
986EFI_STATUS\r
987XhcExecTransfer (\r
a9292c13 988 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 989 IN BOOLEAN CmdTransfer,\r
990 IN URB *Urb,\r
a9292c13 991 IN UINTN Timeout\r
92870c98 992 )\r
993{\r
994 EFI_STATUS Status;\r
995 UINTN Index;\r
996 UINTN Loop;\r
997 UINT8 SlotId;\r
998 UINT8 Dci;\r
999\r
1000 if (CmdTransfer) {\r
1001 SlotId = 0;\r
1002 Dci = 0;\r
1003 } else {\r
a9292c13 1004 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
ce9b5900 1005 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
92870c98 1006 }\r
1007\r
1008 Status = EFI_SUCCESS;\r
a9292c13 1009 Loop = (Timeout * XHC_1_MILLISECOND / XHC_POLL_DELAY) + 1;\r
1010 if (Timeout == 0) {\r
92870c98 1011 Loop = 0xFFFFFFFF;\r
1012 }\r
1013\r
1014 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1015\r
1016 for (Index = 0; Index < Loop; Index++) {\r
1017 Status = XhcCheckUrbResult (Xhc, Urb);\r
1018 if ((Status != EFI_NOT_READY)) {\r
1019 break;\r
1020 }\r
a9292c13 1021 gBS->Stall (XHC_POLL_DELAY);\r
92870c98 1022 }\r
1023\r
1024 return Status;\r
1025}\r
1026\r
1027/**\r
1028 Delete a single asynchronous interrupt transfer for\r
1029 the device and endpoint.\r
1030\r
a9292c13 1031 @param Xhc The XHCI Instance.\r
92870c98 1032 @param DevAddr The address of the target device.\r
1033 @param EpNum The endpoint of the target.\r
1034\r
1035 @retval EFI_SUCCESS An asynchronous transfer is removed.\r
1036 @retval EFI_NOT_FOUND No transfer for the device is found.\r
1037\r
1038**/\r
1039EFI_STATUS\r
1040XhciDelAsyncIntTransfer (\r
a9292c13 1041 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1042 IN UINT8 DevAddr,\r
1043 IN UINT8 EpNum\r
1044 )\r
1045{\r
1046 LIST_ENTRY *Entry;\r
1047 LIST_ENTRY *Next;\r
1048 URB *Urb;\r
1049 EFI_USB_DATA_DIRECTION Direction;\r
92870c98 1050\r
1051 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
1052 EpNum &= 0x0F;\r
1053\r
92870c98 1054 Urb = NULL;\r
1055\r
1056 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1057 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1058 if ((Urb->Ep.DevAddr == DevAddr) &&\r
1059 (Urb->Ep.EpAddr == EpNum) &&\r
1060 (Urb->Ep.Direction == Direction)) {\r
1061 RemoveEntryList (&Urb->UrbList);\r
1062 FreePool (Urb->Data);\r
1063 FreePool (Urb);\r
1064 return EFI_SUCCESS;\r
1065 }\r
1066 }\r
1067\r
1068 return EFI_NOT_FOUND;\r
1069}\r
1070\r
1071/**\r
1072 Remove all the asynchronous interrutp transfers.\r
1073\r
a9292c13 1074 @param Xhc The XHCI Instance.\r
92870c98 1075\r
1076**/\r
1077VOID\r
1078XhciDelAllAsyncIntTransfers (\r
a9292c13 1079 IN USB_XHCI_INSTANCE *Xhc\r
92870c98 1080 )\r
1081{\r
1082 LIST_ENTRY *Entry;\r
1083 LIST_ENTRY *Next;\r
1084 URB *Urb;\r
1085\r
1086 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1087 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1088 RemoveEntryList (&Urb->UrbList);\r
1089 FreePool (Urb->Data);\r
1090 FreePool (Urb);\r
1091 }\r
1092}\r
1093\r
1094/**\r
1095 Update the queue head for next round of asynchronous transfer\r
1096\r
a9292c13 1097 @param Xhc The XHCI Instance.\r
92870c98 1098 @param Urb The URB to update\r
1099\r
1100**/\r
1101VOID\r
1102XhcUpdateAsyncRequest (\r
a9292c13 1103 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1104 IN URB *Urb\r
1105 )\r
1106{\r
1107 EFI_STATUS Status;\r
1108\r
1109 if (Urb->Result == EFI_USB_NOERROR) {\r
1110 Status = XhcCreateTransferTrb (Xhc, Urb);\r
1111 ASSERT_EFI_ERROR (Status);\r
1112 Status = RingIntTransferDoorBell (Xhc, Urb);\r
1113 ASSERT_EFI_ERROR (Status);\r
1114 }\r
1115}\r
1116\r
1117\r
1118/**\r
1119 Interrupt transfer periodic check handler.\r
1120\r
1121 @param Event Interrupt event.\r
a9292c13 1122 @param Context Pointer to USB_XHCI_INSTANCE.\r
92870c98 1123\r
1124**/\r
1125VOID\r
1126EFIAPI\r
1127XhcMonitorAsyncRequests (\r
1128 IN EFI_EVENT Event,\r
1129 IN VOID *Context\r
1130 )\r
1131{\r
a9292c13 1132 USB_XHCI_INSTANCE *Xhc;\r
92870c98 1133 LIST_ENTRY *Entry;\r
1134 LIST_ENTRY *Next;\r
1135 UINT8 *ProcBuf;\r
1136 URB *Urb;\r
1137 UINT8 SlotId;\r
1138 EFI_STATUS Status;\r
1139 EFI_TPL OldTpl;\r
1140\r
1141 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1142\r
a9292c13 1143 Xhc = (USB_XHCI_INSTANCE*) Context;\r
92870c98 1144\r
1145 EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1146 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1147\r
1148 //\r
1149 // Make sure that the device is available before every check.\r
1150 //\r
a9292c13 1151 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
92870c98 1152 if (SlotId == 0) {\r
1153 continue;\r
1154 }\r
1155\r
1156 //\r
1157 // Check the result of URB execution. If it is still\r
1158 // active, check the next one.\r
1159 //\r
1160 Status = XhcCheckUrbResult (Xhc, Urb);\r
1161\r
1162 if (Status == EFI_NOT_READY) {\r
1163 continue;\r
1164 }\r
1165\r
1166 //\r
1167 // Allocate a buffer then copy the transferred data for user.\r
1168 // If failed to allocate the buffer, update the URB for next\r
1169 // round of transfer. Ignore the data of this round.\r
1170 //\r
1171 ProcBuf = NULL;\r
1172 if (Urb->Result == EFI_USB_NOERROR) {\r
1173 ASSERT (Urb->Completed <= Urb->DataLen);\r
1174\r
a9292c13 1175 ProcBuf = AllocateZeroPool (Urb->Completed);\r
92870c98 1176\r
1177 if (ProcBuf == NULL) {\r
1178 XhcUpdateAsyncRequest (Xhc, Urb);\r
1179 continue;\r
1180 }\r
1181\r
1182 CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
1183 }\r
1184\r
1185 XhcUpdateAsyncRequest (Xhc, Urb);\r
1186\r
1187 //\r
1188 // Leave error recovery to its related device driver. A\r
1189 // common case of the error recovery is to re-submit the\r
1190 // interrupt transfer which is linked to the head of the\r
1191 // list. This function scans from head to tail. So the\r
1192 // re-submitted interrupt transfer's callback function\r
1193 // will not be called again in this round. Don't touch this\r
1194 // URB after the callback, it may have been removed by the\r
1195 // callback.\r
1196 //\r
1197 if (Urb->Callback != NULL) {\r
1198 //\r
1199 // Restore the old TPL, USB bus maybe connect device in\r
1200 // his callback. Some drivers may has a lower TPL restriction.\r
1201 //\r
1202 gBS->RestoreTPL (OldTpl);\r
1203 (Urb->Callback) (ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
1204 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1205 }\r
1206\r
1207 if (ProcBuf != NULL) {\r
1208 gBS->FreePool (ProcBuf);\r
1209 }\r
1210 }\r
1211 gBS->RestoreTPL (OldTpl);\r
1212}\r
1213\r
1214/**\r
1215 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
1216\r
a9292c13 1217 @param Xhc The XHCI Instance.\r
92870c98 1218 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
1219 @param Port The port to be polled.\r
1220 @param PortState The port state.\r
1221\r
1222 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
1223 @retval Others Should not appear.\r
1224\r
1225**/\r
1226EFI_STATUS\r
1227EFIAPI\r
1228XhcPollPortStatusChange (\r
a9292c13 1229 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1230 IN USB_DEV_ROUTE ParentRouteChart,\r
1231 IN UINT8 Port,\r
1232 IN EFI_USB_PORT_STATUS *PortState\r
1233 )\r
1234{\r
1235 EFI_STATUS Status;\r
1236 UINT8 Speed;\r
1237 UINT8 SlotId;\r
1238 USB_DEV_ROUTE RouteChart;\r
1239\r
1240 Status = EFI_SUCCESS;\r
1241\r
1242 if (ParentRouteChart.Dword == 0) {\r
a9292c13 1243 RouteChart.Route.RouteString = 0;\r
1244 RouteChart.Route.RootPortNum = Port + 1;\r
1245 RouteChart.Route.TierNum = 1;\r
92870c98 1246 } else {\r
1247 if(Port < 14) {\r
a9292c13 1248 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1249 } else {\r
a9292c13 1250 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
92870c98 1251 }\r
a9292c13 1252 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
1253 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
92870c98 1254 }\r
1255\r
1256 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1257 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {\r
1258 //\r
1259 // Has a device attached, Identify device speed after port is enabled.\r
1260 //\r
1261 Speed = EFI_USB_SPEED_FULL;\r
1262 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
1263 Speed = EFI_USB_SPEED_LOW;\r
1264 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
1265 Speed = EFI_USB_SPEED_HIGH;\r
1266 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
1267 Speed = EFI_USB_SPEED_SUPER;\r
1268 }\r
1269 //\r
1270 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
1271 //\r
a9292c13 1272 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
92870c98 1273 if (SlotId == 0) {\r
1274 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1275 ASSERT_EFI_ERROR (Status);\r
1276 }\r
1277 } else if ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) == 0) {\r
1278 //\r
1279 // Device is detached. Disable the allocated device slot and release resource.\r
1280 //\r
a9292c13 1281 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
92870c98 1282 if (SlotId != 0) {\r
1283 Status = XhcDisableSlotCmd (Xhc, SlotId);\r
1284 ASSERT_EFI_ERROR (Status);\r
1285 }\r
1286 }\r
1287 return Status;\r
1288}\r
1289\r
1290\r
1291/**\r
1292 Calculate the device context index by endpoint address and direction.\r
1293\r
1294 @param EpAddr The target endpoint number.\r
1295 @param Direction The direction of the target endpoint.\r
1296\r
1297 @return The device context index of endpoint.\r
1298\r
1299**/\r
1300UINT8\r
1301XhcEndpointToDci (\r
1302 IN UINT8 EpAddr,\r
1303 IN UINT8 Direction\r
1304 )\r
1305{\r
1306 UINT8 Index;\r
1307\r
1308 if (EpAddr == 0) {\r
1309 return 1;\r
1310 } else {\r
ce9b5900 1311 Index = (UINT8) (2 * EpAddr);\r
92870c98 1312 if (Direction == EfiUsbDataIn) {\r
1313 Index += 1;\r
1314 }\r
1315 return Index;\r
1316 }\r
1317}\r
1318\r
1319/**\r
1320 Find out the slot id according to device address assigned by XHCI's Address_Device cmd.\r
1321\r
a9292c13 1322 @param Xhc The XHCI Instance.\r
92870c98 1323 @param DevAddr The device address of the target device.\r
1324\r
1325 @return The slot id used by the device.\r
1326\r
1327**/\r
1328UINT8\r
92870c98 1329XhcDevAddrToSlotId (\r
a9292c13 1330 IN USB_XHCI_INSTANCE *Xhc,\r
1331 IN UINT8 DevAddr\r
92870c98 1332 )\r
1333{\r
1334 UINT8 Index;\r
1335\r
1336 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1337 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1338 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1339 (Xhc->UsbDevContext[Index + 1].XhciDevAddr == DevAddr)) {\r
92870c98 1340 break;\r
1341 }\r
1342 }\r
1343\r
1344 if (Index == 255) {\r
1345 return 0;\r
1346 }\r
1347\r
a9292c13 1348 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1349}\r
1350\r
1351/**\r
1352 Find out the actual device address according to the requested device address from UsbBus.\r
1353\r
a9292c13 1354 @param Xhc The XHCI Instance.\r
1355 @param BusDevAddr The requested device address by UsbBus upper driver.\r
92870c98 1356\r
1357 @return The actual device address assigned to the device.\r
1358\r
1359**/\r
1360UINT8\r
1361EFIAPI\r
1362XhcBusDevAddrToSlotId (\r
a9292c13 1363 IN USB_XHCI_INSTANCE *Xhc,\r
1364 IN UINT8 BusDevAddr\r
92870c98 1365 )\r
1366{\r
1367 UINT8 Index;\r
1368\r
1369 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1370 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1371 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1372 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr)) {\r
92870c98 1373 break;\r
1374 }\r
1375 }\r
1376\r
1377 if (Index == 255) {\r
1378 return 0;\r
1379 }\r
1380\r
a9292c13 1381 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1382}\r
1383\r
1384/**\r
1385 Find out the slot id according to the device's route string.\r
1386\r
a9292c13 1387 @param Xhc The XHCI Instance.\r
1388 @param RouteString The route string described the device location.\r
92870c98 1389\r
1390 @return The slot id used by the device.\r
1391\r
1392**/\r
1393UINT8\r
1394EFIAPI\r
1395XhcRouteStringToSlotId (\r
a9292c13 1396 IN USB_XHCI_INSTANCE *Xhc,\r
1397 IN USB_DEV_ROUTE RouteString\r
92870c98 1398 )\r
1399{\r
1400 UINT8 Index;\r
1401\r
1402 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1403 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1404 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1405 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword)) {\r
92870c98 1406 break;\r
1407 }\r
1408 }\r
1409\r
1410 if (Index == 255) {\r
1411 return 0;\r
1412 }\r
1413\r
a9292c13 1414 return Xhc->UsbDevContext[Index + 1].SlotId;\r
92870c98 1415}\r
1416\r
1417/**\r
1418 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
1419\r
a9292c13 1420 @param Xhc The XHCI Instance.\r
92870c98 1421 @param EvtRing The event ring to sync.\r
1422\r
1423 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
1424\r
1425**/\r
1426EFI_STATUS\r
1427EFIAPI\r
1428XhcSyncEventRing (\r
a9292c13 1429 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1430 IN EVENT_RING *EvtRing\r
1431 )\r
1432{\r
1433 UINTN Index;\r
a9292c13 1434 TRB_TEMPLATE *EvtTrb1;\r
1435 TRB_TEMPLATE *EvtTrb2;\r
1436 TRB_TEMPLATE *XhcDequeue;\r
92870c98 1437\r
1438 ASSERT (EvtRing != NULL);\r
1439\r
1440 //\r
1441 // Calculate the EventRingEnqueue and EventRingCCS.\r
1442 // Note: only support single Segment\r
1443 //\r
1444 EvtTrb1 = EvtRing->EventRingSeg0;\r
1445 EvtTrb2 = EvtRing->EventRingSeg0;\r
1446\r
1447 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
1448 if (EvtTrb1->CycleBit != EvtTrb2->CycleBit) {\r
1449 break;\r
1450 }\r
1451 EvtTrb1++;\r
1452 }\r
1453\r
1454 if (Index < EvtRing->TrbNumber) {\r
1455 EvtRing->EventRingEnqueue = EvtTrb1;\r
1456 EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 1 : 0;\r
1457 } else {\r
1458 EvtRing->EventRingEnqueue = EvtTrb2;\r
1459 EvtRing->EventRingCCS = (EvtTrb2->CycleBit) ? 0 : 1;\r
1460 }\r
1461\r
1462 //\r
1463 // Apply the EventRingDequeue to Xhc\r
1464 //\r
a9292c13 1465 XhcDequeue = (TRB_TEMPLATE *)(UINTN) XhcReadRuntimeReg64 (\r
1466 Xhc,\r
1467 XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter)\r
1468 );\r
92870c98 1469\r
ce9b5900 1470 if (((UINT64)(UINTN)XhcDequeue & (~0x0F)) != ((UINT64)(UINTN)EvtRing->EventRingDequeue & (~0x0F))) {\r
92870c98 1471 XhcWriteRuntimeReg64 (\r
1472 Xhc,\r
1473 XHC_ERDP_OFFSET + (32 * EvtRing->EventInterrupter),\r
ce9b5900 1474 (UINT64)(UINTN)EvtRing->EventRingDequeue | BIT3\r
92870c98 1475 );\r
1476 }\r
1477\r
1478 return EFI_SUCCESS;\r
1479}\r
1480\r
1481/**\r
1482 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
1483\r
a9292c13 1484 @param Xhc The XHCI Instance.\r
92870c98 1485 @param TrsRing The transfer ring to sync.\r
1486\r
1487 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
1488\r
1489**/\r
1490EFI_STATUS\r
1491EFIAPI\r
1492XhcSyncTrsRing (\r
a9292c13 1493 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1494 IN TRANSFER_RING *TrsRing\r
1495 )\r
1496{\r
1497 UINTN Index;\r
a9292c13 1498 TRB_TEMPLATE *TrsTrb;\r
92870c98 1499\r
1500 ASSERT (TrsRing != NULL);\r
1501 //\r
1502 // Calculate the latest RingEnqueue and RingPCS\r
1503 //\r
1504 TrsTrb = TrsRing->RingEnqueue;\r
1505 ASSERT (TrsTrb != NULL);\r
1506\r
1507 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
1508 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
1509 break;\r
1510 }\r
1511 TrsTrb++;\r
1512 if ((UINT8) TrsTrb->Type == TRB_TYPE_LINK) {\r
a9292c13 1513 ASSERT (((LINK_TRB*)TrsTrb)->TC != 0);\r
92870c98 1514 //\r
1515 // set cycle bit in Link TRB as normal\r
1516 //\r
a9292c13 1517 ((LINK_TRB*)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
92870c98 1518 //\r
1519 // Toggle PCS maintained by software\r
1520 //\r
1521 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
a9292c13 1522 TrsTrb = (TRB_TEMPLATE *)(UINTN)((TrsTrb->Parameter1 | ((UINT64)TrsTrb->Parameter2 << 32)) & ~0x0F);\r
92870c98 1523 }\r
1524 }\r
1525\r
1526 ASSERT (Index != TrsRing->TrbNumber);\r
1527\r
1528 if (TrsTrb != TrsRing->RingEnqueue) {\r
1529 TrsRing->RingEnqueue = TrsTrb;\r
1530 }\r
1531\r
1532 //\r
1533 // Clear the Trb context for enqueue, but reserve the PCS bit\r
1534 //\r
a9292c13 1535 TrsTrb->Parameter1 = 0;\r
1536 TrsTrb->Parameter2 = 0;\r
1537 TrsTrb->Status = 0;\r
1538 TrsTrb->RsvdZ1 = 0;\r
1539 TrsTrb->Type = 0;\r
1540 TrsTrb->Control = 0;\r
92870c98 1541\r
1542 return EFI_SUCCESS;\r
1543}\r
1544\r
1545/**\r
1546 Check if there is a new generated event.\r
1547\r
a9292c13 1548 @param Xhc The XHCI Instance.\r
92870c98 1549 @param EvtRing The event ring to check.\r
1550 @param NewEvtTrb The new event TRB found.\r
1551\r
1552 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
1553 @retval EFI_NOT_READY The event ring has no new event.\r
1554\r
1555**/\r
1556EFI_STATUS\r
1557EFIAPI\r
1558XhcCheckNewEvent (\r
a9292c13 1559 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1560 IN EVENT_RING *EvtRing,\r
a9292c13 1561 OUT TRB_TEMPLATE **NewEvtTrb\r
92870c98 1562 )\r
1563{\r
1564 EFI_STATUS Status;\r
a9292c13 1565 TRB_TEMPLATE*EvtTrb;\r
92870c98 1566\r
1567 ASSERT (EvtRing != NULL);\r
1568\r
1569 EvtTrb = EvtRing->EventRingDequeue;\r
1570 *NewEvtTrb = EvtRing->EventRingDequeue;\r
1571\r
1572 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
1573 return EFI_NOT_READY;\r
1574 }\r
1575\r
1576 Status = EFI_SUCCESS;\r
1577\r
a9292c13 1578 if (((EvtTrb->Status >> 24) & 0xFF) != TRB_COMPLETION_SUCCESS) {\r
92870c98 1579 Status = EFI_DEVICE_ERROR;\r
1580 }\r
1581\r
1582 EvtRing->EventRingDequeue++;\r
1583 //\r
1584 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
1585 //\r
a9292c13 1586 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN) EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
92870c98 1587 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
1588 }\r
1589\r
1590 return Status;\r
1591}\r
1592\r
1593/**\r
1594 Ring the door bell to notify XHCI there is a transaction to be executed.\r
1595\r
a9292c13 1596 @param Xhc The XHCI Instance.\r
92870c98 1597 @param SlotId The slot id of the target device.\r
1598 @param Dci The device context index of the target slot or endpoint.\r
1599\r
1600 @retval EFI_SUCCESS Successfully ring the door bell.\r
1601\r
1602**/\r
1603EFI_STATUS\r
1604EFIAPI\r
1605XhcRingDoorBell (\r
a9292c13 1606 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1607 IN UINT8 SlotId,\r
1608 IN UINT8 Dci\r
1609 )\r
1610{\r
1611 if (SlotId == 0) {\r
1612 XhcWriteDoorBellReg (Xhc, 0, 0);\r
1613 } else {\r
1614 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
1615 }\r
1616\r
1617 return EFI_SUCCESS;\r
1618}\r
1619\r
1620/**\r
1621 Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
1622\r
a9292c13 1623 @param Xhc The XHCI Instance.\r
92870c98 1624 @param Urb The URB to be rung.\r
1625\r
1626 @retval EFI_SUCCESS Successfully ring the door bell.\r
1627\r
1628**/\r
1629EFI_STATUS\r
1630RingIntTransferDoorBell (\r
a9292c13 1631 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1632 IN URB *Urb\r
1633 )\r
1634{\r
1635 UINT8 SlotId;\r
1636 UINT8 Dci;\r
1637\r
a9292c13 1638 SlotId = XhcDevAddrToSlotId(Xhc, Urb->Ep.DevAddr);\r
ce9b5900 1639 Dci = XhcEndpointToDci(Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
92870c98 1640 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1641 return EFI_SUCCESS;\r
1642}\r
1643\r
1644/**\r
1645 Assign and initialize the device slot for a new device.\r
1646\r
a9292c13 1647 @param Xhc The XHCI Instance.\r
92870c98 1648 @param ParentRouteChart The route string pointed to the parent device.\r
1649 @param ParentPort The port at which the device is located.\r
1650 @param RouteChart The route string pointed to the device.\r
1651 @param DeviceSpeed The device speed.\r
1652\r
1653 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
1654\r
1655**/\r
1656EFI_STATUS\r
1657EFIAPI\r
1658XhcInitializeDeviceSlot (\r
a9292c13 1659 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1660 IN USB_DEV_ROUTE ParentRouteChart,\r
1661 IN UINT16 ParentPort,\r
1662 IN USB_DEV_ROUTE RouteChart,\r
1663 IN UINT8 DeviceSpeed\r
1664 )\r
1665{\r
a9292c13 1666 EFI_STATUS Status;\r
1667 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
1668 INPUT_CONTEXT *InputContext;\r
1669 DEVICE_CONTEXT *OutputContext;\r
1670 TRANSFER_RING *EndpointTransferRing;\r
1671 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
1672 UINT8 DeviceAddress;\r
1673 CMD_TRB_ENABLE_SLOT CmdTrb;\r
1674 UINT8 SlotId;\r
1675 UINT8 ParentSlotId;\r
1676 DEVICE_CONTEXT *ParentDeviceContext;\r
1677\r
1678 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
92870c98 1679 CmdTrb.CycleBit = 1;\r
1680 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
1681\r
1682 Status = XhcCmdTransfer (\r
1683 Xhc,\r
a9292c13 1684 (TRB_TEMPLATE *) (UINTN) &CmdTrb,\r
92870c98 1685 XHC_GENERIC_TIMEOUT,\r
a9292c13 1686 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 1687 );\r
1688 ASSERT_EFI_ERROR (Status);\r
1689 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
1690 DEBUG ((EFI_D_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
1691 SlotId = (UINT8)EvtTrb->SlotId;\r
1692 ASSERT (SlotId != 0);\r
1693\r
a9292c13 1694 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
1695 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
1696 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
1697 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
1698 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
92870c98 1699\r
1700 //\r
1701 // 4.3.3 Device Slot Initialization\r
1702 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
1703 //\r
a9292c13 1704 InputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));\r
92870c98 1705 ASSERT (InputContext != NULL);\r
1706 ASSERT (((UINTN) InputContext & 0x3F) == 0);\r
a9292c13 1707 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
92870c98 1708\r
a9292c13 1709 Xhc->UsbDevContext[SlotId].InputContext = (VOID *) InputContext;\r
92870c98 1710\r
1711 //\r
1712 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
1713 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
1714 // Context are affected by the command.\r
1715 //\r
1716 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
1717\r
1718 //\r
1719 // 3) Initialize the Input Slot Context data structure\r
1720 //\r
a9292c13 1721 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
92870c98 1722 InputContext->Slot.Speed = DeviceSpeed + 1;\r
1723 InputContext->Slot.ContextEntries = 1;\r
a9292c13 1724 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
92870c98 1725\r
a9292c13 1726 if (RouteChart.Route.RouteString) {\r
92870c98 1727 //\r
1728 // The device is behind of hub device.\r
1729 //\r
a9292c13 1730 ParentSlotId = XhcRouteStringToSlotId(Xhc, ParentRouteChart);\r
92870c98 1731 ASSERT (ParentSlotId != 0);\r
1732 //\r
1733 //if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
1734 //\r
a9292c13 1735 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
92870c98 1736 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
1737 (ParentDeviceContext->Slot.TTHubSlotId == 0)) {\r
1738 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
1739 //\r
1740 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
1741 // environment from Full/Low speed signaling environment for a device\r
1742 //\r
1743 InputContext->Slot.TTPortNum = ParentPort;\r
1744 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
1745 }\r
1746 } else {\r
1747 //\r
1748 // Inherit the TT parameters from parent device.\r
1749 //\r
1750 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
1751 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
1752 //\r
1753 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
1754 //\r
1755 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1756 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
1757 }\r
1758 }\r
1759 }\r
1760\r
1761 //\r
1762 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
1763 //\r
a9292c13 1764 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
1765 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
1766 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
92870c98 1767 //\r
1768 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
1769 //\r
1770 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
1771\r
1772 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
1773 InputContext->EP[0].MaxPacketSize = 512;\r
1774 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
1775 InputContext->EP[0].MaxPacketSize = 64;\r
1776 } else {\r
1777 InputContext->EP[0].MaxPacketSize = 8;\r
1778 }\r
1779 //\r
1780 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
1781 // 1KB, and Bulk and Isoch endpoints 3KB.\r
1782 //\r
1783 InputContext->EP[0].AverageTRBLength = 8;\r
1784 InputContext->EP[0].MaxBurstSize = 0;\r
1785 InputContext->EP[0].Interval = 0;\r
1786 InputContext->EP[0].MaxPStreams = 0;\r
1787 InputContext->EP[0].Mult = 0;\r
1788 InputContext->EP[0].CErr = 3;\r
1789\r
1790 //\r
1791 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
1792 //\r
a9292c13 1793 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0) | BIT0;\r
1794 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0);\r
92870c98 1795\r
1796 //\r
1797 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
1798 //\r
a9292c13 1799 OutputContext = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));\r
1800 ASSERT (OutputContext != NULL);\r
1801 ASSERT (((UINTN) OutputContext & 0x3F) == 0);\r
1802 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
92870c98 1803\r
a9292c13 1804 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
92870c98 1805 //\r
1806 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
1807 // a pointer to the Output Device Context data structure (6.2.1).\r
1808 //\r
a9292c13 1809 Xhc->DCBAA[SlotId] = (UINT64) (UINTN) OutputContext;\r
92870c98 1810\r
1811 //\r
1812 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
1813 // Context data structure described above.\r
1814 //\r
1815 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
a9292c13 1816 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (Xhc->UsbDevContext[SlotId].InputContext);\r
1817 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (Xhc->UsbDevContext[SlotId].InputContext);\r
92870c98 1818 CmdTrbAddr.CycleBit = 1;\r
1819 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
a9292c13 1820 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 1821 Status = XhcCmdTransfer (\r
1822 Xhc,\r
a9292c13 1823 (TRB_TEMPLATE *) (UINTN) &CmdTrbAddr,\r
92870c98 1824 XHC_GENERIC_TIMEOUT,\r
a9292c13 1825 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 1826 );\r
1827 ASSERT (!EFI_ERROR(Status));\r
1828\r
a9292c13 1829 DeviceAddress = (UINT8) ((DEVICE_CONTEXT *) OutputContext)->Slot.DeviceAddress;\r
92870c98 1830 DEBUG ((EFI_D_INFO, " Address %d assigned succeefully\n", DeviceAddress));\r
1831\r
a9292c13 1832 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
92870c98 1833\r
1834 return Status;\r
1835}\r
1836\r
1837/**\r
1838 Disable the specified device slot.\r
1839\r
a9292c13 1840 @param Xhc The XHCI Instance.\r
92870c98 1841 @param SlotId The slot id to be disabled.\r
1842\r
1843 @retval EFI_SUCCESS Successfully disable the device slot.\r
1844\r
1845**/\r
1846EFI_STATUS\r
1847EFIAPI\r
1848XhcDisableSlotCmd (\r
a9292c13 1849 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1850 IN UINT8 SlotId\r
1851 )\r
1852{\r
1853 EFI_STATUS Status;\r
a9292c13 1854 TRB_TEMPLATE *EvtTrb;\r
1855 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
92870c98 1856 UINT8 Index;\r
1857 VOID *RingSeg;\r
1858\r
1859 //\r
1860 // Disable the device slots occupied by these devices on its downstream ports.\r
1861 // Entry 0 is reserved.\r
1862 //\r
1863 for (Index = 0; Index < 255; Index++) {\r
a9292c13 1864 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
1865 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
1866 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword)) {\r
92870c98 1867 continue;\r
1868 }\r
1869\r
a9292c13 1870 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
92870c98 1871\r
1872 if (EFI_ERROR (Status)) {\r
1873 DEBUG ((EFI_D_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
a9292c13 1874 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
92870c98 1875 }\r
1876 }\r
1877\r
1878 //\r
1879 // Construct the disable slot command\r
1880 //\r
1881 DEBUG ((EFI_D_INFO, "Disable device slot %d!\n", SlotId));\r
1882\r
1883 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
1884 CmdTrbDisSlot.CycleBit = 1;\r
1885 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
1886 CmdTrbDisSlot.SlotId = SlotId;\r
1887 Status = XhcCmdTransfer (\r
1888 Xhc,\r
a9292c13 1889 (TRB_TEMPLATE *) (UINTN) &CmdTrbDisSlot,\r
92870c98 1890 XHC_GENERIC_TIMEOUT,\r
a9292c13 1891 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 1892 );\r
1893 ASSERT_EFI_ERROR(Status);\r
1894 //\r
1895 // Free the slot's device context entry\r
1896 //\r
1897 Xhc->DCBAA[SlotId] = 0;\r
1898\r
1899 //\r
1900 // Free the slot related data structure\r
1901 //\r
1902 for (Index = 0; Index < 31; Index++) {\r
a9292c13 1903 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
1904 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
92870c98 1905 if (RingSeg != NULL) {\r
a9292c13 1906 FreePages (RingSeg, EFI_SIZE_TO_PAGES (sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER));\r
92870c98 1907 }\r
a9292c13 1908 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
92870c98 1909 }\r
1910 }\r
1911\r
a9292c13 1912 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
1913 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
1914 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
92870c98 1915 }\r
1916 }\r
1917\r
a9292c13 1918 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
1919 FreePages (Xhc->UsbDevContext[SlotId].InputContext, EFI_SIZE_TO_PAGES (sizeof (INPUT_CONTEXT)));\r
92870c98 1920 }\r
1921\r
a9292c13 1922 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
1923 FreePages (Xhc->UsbDevContext[SlotId].OutputContext, EFI_SIZE_TO_PAGES (sizeof (DEVICE_CONTEXT)));\r
92870c98 1924 }\r
1925 //\r
1926 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
1927 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
1928 // remove urb from XHCI's asynchronous transfer list.\r
1929 //\r
a9292c13 1930 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
92870c98 1931\r
1932 return Status;\r
1933}\r
1934\r
1935/**\r
1936 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
1937\r
a9292c13 1938 @param Xhc The XHCI Instance.\r
92870c98 1939 @param SlotId The slot id to be configured.\r
1940 @param DeviceSpeed The device's speed.\r
1941 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
1942\r
1943 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
1944\r
1945**/\r
1946EFI_STATUS\r
1947EFIAPI\r
1948XhcSetConfigCmd (\r
a9292c13 1949 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 1950 IN UINT8 SlotId,\r
a9292c13 1951 IN UINT8 DeviceSpeed,\r
92870c98 1952 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
1953 )\r
1954{\r
a9292c13 1955 EFI_STATUS Status;\r
1956\r
1957 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
1958 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
1959 UINT8 Index;\r
1960 UINTN NumEp;\r
1961 UINTN EpIndex;\r
1962 UINT8 EpAddr;\r
1963 UINT8 Direction;\r
1964 UINT8 Dci;\r
1965 UINT8 MaxDci;\r
1966 UINT32 PhyAddr;\r
1967 UINT8 Interval;\r
1968\r
1969 TRANSFER_RING *EndpointTransferRing;\r
1970 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
1971 INPUT_CONTEXT *InputContext;\r
1972 DEVICE_CONTEXT *OutputContext;\r
1973 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
92870c98 1974 //\r
1975 // 4.6.6 Configure Endpoint\r
1976 //\r
a9292c13 1977 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
1978 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
92870c98 1979 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
a9292c13 1980 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
92870c98 1981\r
1982 ASSERT (ConfigDesc != NULL);\r
1983\r
1984 MaxDci = 0;\r
1985\r
1986 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
1987 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
1988 while (IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) {\r
1989 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
1990 }\r
1991\r
1992 NumEp = IfDesc->NumEndpoints;\r
1993\r
1994 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
1995 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
1996 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
1997 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
1998 }\r
1999\r
ce9b5900 2000 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
92870c98 2001 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2002\r
2003 Dci = XhcEndpointToDci (EpAddr, Direction);\r
a9292c13 2004 ASSERT (Dci < 32);\r
92870c98 2005 if (Dci > MaxDci) {\r
2006 MaxDci = Dci;\r
2007 }\r
2008\r
2009 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2010 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2011\r
2012 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2013 //\r
2014 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2015 //\r
2016 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2017 } else {\r
2018 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2019 }\r
2020\r
2021 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2022 case USB_ENDPOINT_BULK:\r
2023 if (Direction == EfiUsbDataIn) {\r
2024 InputContext->EP[Dci-1].CErr = 3;\r
2025 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2026 } else {\r
2027 InputContext->EP[Dci-1].CErr = 3;\r
2028 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2029 }\r
2030\r
2031 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
a9292c13 2032 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2033 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2034 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2035 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
92870c98 2036 }\r
2037\r
2038 break;\r
2039 case USB_ENDPOINT_ISO:\r
2040 if (Direction == EfiUsbDataIn) {\r
2041 InputContext->EP[Dci-1].CErr = 0;\r
2042 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2043 } else {\r
2044 InputContext->EP[Dci-1].CErr = 0;\r
2045 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2046 }\r
2047 break;\r
2048 case USB_ENDPOINT_INTERRUPT:\r
2049 if (Direction == EfiUsbDataIn) {\r
2050 InputContext->EP[Dci-1].CErr = 3;\r
2051 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2052 } else {\r
2053 InputContext->EP[Dci-1].CErr = 3;\r
2054 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2055 }\r
2056 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2057 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2058 //\r
2059 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2060 //\r
2061 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2062 Interval = EpDesc->Interval;\r
2063 //\r
a9292c13 2064 // Hard code the interval to MAX first, need calculate through the bInterval field of Endpoint descriptor.\r
92870c98 2065 //\r
2066 InputContext->EP[Dci-1].Interval = 6;\r
a9292c13 2067 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
92870c98 2068 Interval = EpDesc->Interval;\r
a9292c13 2069 ASSERT (Interval >= 1 && Interval <= 16);\r
2070 //\r
2071 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2072 //\r
2073 InputContext->EP[Dci-1].Interval = Interval - 1;\r
92870c98 2074 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2075 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2076 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2077 InputContext->EP[Dci-1].CErr = 3;\r
2078 }\r
2079\r
a9292c13 2080 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2081 EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
2082 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
2083 CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
92870c98 2084 }\r
2085 break;\r
2086\r
2087 case USB_ENDPOINT_CONTROL:\r
2088 default:\r
2089 ASSERT (0);\r
2090 break;\r
2091 }\r
2092\r
a9292c13 2093 PhyAddr = XHC_LOW_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);\r
92870c98 2094 PhyAddr &= ~(0x0F);\r
a9292c13 2095 PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
92870c98 2096 InputContext->EP[Dci-1].PtrLo = PhyAddr;\r
a9292c13 2097 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0);\r
92870c98 2098\r
2099 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2100 }\r
2101 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
2102 }\r
2103\r
2104 InputContext->InputControlContext.Dword2 |= BIT0;\r
2105 InputContext->Slot.ContextEntries = MaxDci;\r
2106 //\r
2107 // configure endpoint\r
2108 //\r
2109 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
2110 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);\r
2111 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);\r
2112 CmdTrbCfgEP.CycleBit = 1;\r
2113 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 2114 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2115 DEBUG ((EFI_D_INFO, "Configure Endpoint\n"));\r
2116 Status = XhcCmdTransfer (\r
2117 Xhc,\r
a9292c13 2118 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 2119 XHC_GENERIC_TIMEOUT,\r
a9292c13 2120 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2121 );\r
2122 ASSERT_EFI_ERROR(Status);\r
2123\r
2124 return Status;\r
2125}\r
2126\r
2127/**\r
2128 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
2129\r
a9292c13 2130 @param Xhc The XHCI Instance.\r
92870c98 2131 @param SlotId The slot id to be evaluated.\r
2132 @param MaxPacketSize The max packet size supported by the device control transfer.\r
2133\r
2134 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
2135\r
2136**/\r
2137EFI_STATUS\r
2138EFIAPI\r
2139XhcEvaluateContext (\r
a9292c13 2140 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2141 IN UINT8 SlotId,\r
2142 IN UINT32 MaxPacketSize\r
2143 )\r
2144{\r
a9292c13 2145 EFI_STATUS Status;\r
2146 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
2147 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2148 INPUT_CONTEXT *InputContext;\r
92870c98 2149\r
a9292c13 2150 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
92870c98 2151\r
2152 //\r
2153 // 4.6.7 Evaluate Context\r
2154 //\r
a9292c13 2155 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
92870c98 2156 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2157\r
2158 InputContext->InputControlContext.Dword2 |= BIT1;\r
2159 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
2160\r
2161 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
2162 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (InputContext);\r
2163 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (InputContext);\r
2164 CmdTrbEvalu.CycleBit = 1;\r
2165 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
a9292c13 2166 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2167 DEBUG ((EFI_D_INFO, "Evaluate context\n"));\r
2168 Status = XhcCmdTransfer (\r
2169 Xhc,\r
a9292c13 2170 (TRB_TEMPLATE *) (UINTN) &CmdTrbEvalu,\r
92870c98 2171 XHC_GENERIC_TIMEOUT,\r
a9292c13 2172 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2173 );\r
2174 ASSERT (!EFI_ERROR(Status));\r
2175\r
2176 return Status;\r
2177}\r
2178\r
2179/**\r
2180 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
2181\r
a9292c13 2182 @param Xhc The XHCI Instance.\r
92870c98 2183 @param SlotId The slot id to be configured.\r
2184 @param PortNum The total number of downstream port supported by the hub.\r
2185 @param TTT The TT think time of the hub device.\r
2186 @param MTT The multi-TT of the hub device.\r
2187\r
2188 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
2189\r
2190**/\r
2191EFI_STATUS\r
2192XhcConfigHubContext (\r
a9292c13 2193 IN USB_XHCI_INSTANCE *Xhc,\r
92870c98 2194 IN UINT8 SlotId,\r
2195 IN UINT8 PortNum,\r
2196 IN UINT8 TTT,\r
2197 IN UINT8 MTT\r
2198 )\r
2199{\r
a9292c13 2200 EFI_STATUS Status;\r
92870c98 2201\r
a9292c13 2202 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2203 INPUT_CONTEXT *InputContext;\r
2204 DEVICE_CONTEXT *OutputContext;\r
2205 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
92870c98 2206\r
a9292c13 2207 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
2208 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
2209 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
92870c98 2210\r
2211 //\r
2212 // 4.6.7 Evaluate Context\r
2213 //\r
2214 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2215\r
2216 InputContext->InputControlContext.Dword2 |= BIT0;\r
2217\r
2218 //\r
2219 // Copy the slot context from OutputContext to Input context\r
2220 //\r
a9292c13 2221 CopyMem(&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
92870c98 2222 InputContext->Slot.Hub = 1;\r
2223 InputContext->Slot.PortNum = PortNum;\r
2224 InputContext->Slot.TTT = TTT;\r
2225 InputContext->Slot.MTT = MTT;\r
2226\r
2227 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
2228 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (InputContext);\r
2229 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (InputContext);\r
2230 CmdTrbCfgEP.CycleBit = 1;\r
2231 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
a9292c13 2232 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
92870c98 2233 DEBUG ((EFI_D_INFO, "Configure Hub Slot Context\n"));\r
2234 Status = XhcCmdTransfer (\r
2235 Xhc,\r
a9292c13 2236 (TRB_TEMPLATE *) (UINTN) &CmdTrbCfgEP,\r
92870c98 2237 XHC_GENERIC_TIMEOUT,\r
a9292c13 2238 (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
92870c98 2239 );\r
2240 ASSERT (!EFI_ERROR(Status));\r
2241\r
2242 return Status;\r
2243}\r
2244\r