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