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