]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / XhciSched.c
... / ...
CommitLineData
1/** @file\r
2\r
3 XHCI transfer scheduling routines.\r
4\r
5Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.<BR>\r
6Copyright (c) Microsoft Corporation.<BR>\r
7Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.<BR>\r
8SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12#include "Xhci.h"\r
13\r
14/**\r
15 Create a command transfer TRB to support XHCI command interfaces.\r
16\r
17 @param Xhc The XHCI Instance.\r
18 @param CmdTrb The cmd TRB to be executed.\r
19\r
20 @return Created URB or NULL.\r
21\r
22**/\r
23URB *\r
24XhcCreateCmdTrb (\r
25 IN USB_XHCI_INSTANCE *Xhc,\r
26 IN TRB_TEMPLATE *CmdTrb\r
27 )\r
28{\r
29 URB *Urb;\r
30\r
31 Urb = AllocateZeroPool (sizeof (URB));\r
32 if (Urb == NULL) {\r
33 return NULL;\r
34 }\r
35\r
36 Urb->Signature = XHC_URB_SIG;\r
37\r
38 Urb->Ring = &Xhc->CmdRing;\r
39 XhcSyncTrsRing (Xhc, Urb->Ring);\r
40 Urb->TrbNum = 1;\r
41 Urb->TrbStart = Urb->Ring->RingEnqueue;\r
42 CopyMem (Urb->TrbStart, CmdTrb, sizeof (TRB_TEMPLATE));\r
43 Urb->TrbStart->CycleBit = Urb->Ring->RingPCS & BIT0;\r
44 Urb->TrbEnd = Urb->TrbStart;\r
45\r
46 return Urb;\r
47}\r
48\r
49/**\r
50 Execute a XHCI cmd TRB pointed by CmdTrb.\r
51\r
52 @param Xhc The XHCI Instance.\r
53 @param CmdTrb The cmd TRB to be executed.\r
54 @param Timeout Indicates the maximum time, in millisecond, which the\r
55 transfer is allowed to complete.\r
56 @param EvtTrb The event TRB corresponding to the cmd TRB.\r
57\r
58 @retval EFI_SUCCESS The transfer was completed successfully.\r
59 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
60 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
61 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
62\r
63**/\r
64EFI_STATUS\r
65EFIAPI\r
66XhcCmdTransfer (\r
67 IN USB_XHCI_INSTANCE *Xhc,\r
68 IN TRB_TEMPLATE *CmdTrb,\r
69 IN UINTN Timeout,\r
70 OUT TRB_TEMPLATE **EvtTrb\r
71 )\r
72{\r
73 EFI_STATUS Status;\r
74 URB *Urb;\r
75\r
76 //\r
77 // Validate the parameters\r
78 //\r
79 if ((Xhc == NULL) || (CmdTrb == NULL)) {\r
80 return EFI_INVALID_PARAMETER;\r
81 }\r
82\r
83 Status = EFI_DEVICE_ERROR;\r
84\r
85 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
86 DEBUG ((DEBUG_ERROR, "XhcCmdTransfer: HC is halted\n"));\r
87 goto ON_EXIT;\r
88 }\r
89\r
90 //\r
91 // Create a new URB, then poll the execution status.\r
92 //\r
93 Urb = XhcCreateCmdTrb (Xhc, CmdTrb);\r
94\r
95 if (Urb == NULL) {\r
96 DEBUG ((DEBUG_ERROR, "XhcCmdTransfer: failed to create URB\n"));\r
97 Status = EFI_OUT_OF_RESOURCES;\r
98 goto ON_EXIT;\r
99 }\r
100\r
101 Status = XhcExecTransfer (Xhc, TRUE, Urb, Timeout);\r
102 *EvtTrb = Urb->EvtTrb;\r
103\r
104 if (Urb->Result == EFI_USB_NOERROR) {\r
105 Status = EFI_SUCCESS;\r
106 }\r
107\r
108 XhcFreeUrb (Xhc, Urb);\r
109\r
110ON_EXIT:\r
111 return Status;\r
112}\r
113\r
114/**\r
115 Create a new URB for a new transaction.\r
116\r
117 @param Xhc The XHCI Instance\r
118 @param BusAddr The logical device address assigned by UsbBus driver\r
119 @param EpAddr Endpoint addrress\r
120 @param DevSpeed The device speed\r
121 @param MaxPacket The max packet length of the endpoint\r
122 @param Type The transaction type\r
123 @param Request The standard USB request for control transfer\r
124 @param Data The user data to transfer\r
125 @param DataLen The length of data buffer\r
126 @param Callback The function to call when data is transferred\r
127 @param Context The context to the callback\r
128\r
129 @return Created URB or NULL\r
130\r
131**/\r
132URB *\r
133XhcCreateUrb (\r
134 IN USB_XHCI_INSTANCE *Xhc,\r
135 IN UINT8 BusAddr,\r
136 IN UINT8 EpAddr,\r
137 IN UINT8 DevSpeed,\r
138 IN UINTN MaxPacket,\r
139 IN UINTN Type,\r
140 IN EFI_USB_DEVICE_REQUEST *Request,\r
141 IN VOID *Data,\r
142 IN UINTN DataLen,\r
143 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
144 IN VOID *Context\r
145 )\r
146{\r
147 USB_ENDPOINT *Ep;\r
148 EFI_STATUS Status;\r
149 URB *Urb;\r
150\r
151 Urb = AllocateZeroPool (sizeof (URB));\r
152 if (Urb == NULL) {\r
153 return NULL;\r
154 }\r
155\r
156 Urb->Signature = XHC_URB_SIG;\r
157 InitializeListHead (&Urb->UrbList);\r
158\r
159 Ep = &Urb->Ep;\r
160 Ep->BusAddr = BusAddr;\r
161 Ep->EpAddr = (UINT8)(EpAddr & 0x0F);\r
162 Ep->Direction = ((EpAddr & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
163 Ep->DevSpeed = DevSpeed;\r
164 Ep->MaxPacket = MaxPacket;\r
165 Ep->Type = Type;\r
166\r
167 Urb->Request = Request;\r
168 Urb->Data = Data;\r
169 Urb->DataLen = DataLen;\r
170 Urb->Callback = Callback;\r
171 Urb->Context = Context;\r
172\r
173 Status = XhcCreateTransferTrb (Xhc, Urb);\r
174 ASSERT_EFI_ERROR (Status);\r
175 if (EFI_ERROR (Status)) {\r
176 DEBUG ((DEBUG_ERROR, "XhcCreateUrb: XhcCreateTransferTrb Failed, Status = %r\n", Status));\r
177 FreePool (Urb);\r
178 Urb = NULL;\r
179 }\r
180\r
181 return Urb;\r
182}\r
183\r
184/**\r
185 Free an allocated URB.\r
186\r
187 @param Xhc The XHCI device.\r
188 @param Urb The URB to free.\r
189\r
190**/\r
191VOID\r
192XhcFreeUrb (\r
193 IN USB_XHCI_INSTANCE *Xhc,\r
194 IN URB *Urb\r
195 )\r
196{\r
197 if ((Xhc == NULL) || (Urb == NULL)) {\r
198 return;\r
199 }\r
200\r
201 if (Urb->DataMap != NULL) {\r
202 Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);\r
203 }\r
204\r
205 FreePool (Urb);\r
206}\r
207\r
208/**\r
209 Create a transfer TRB.\r
210\r
211 @param Xhc The XHCI Instance\r
212 @param Urb The urb used to construct the transfer TRB.\r
213\r
214 @return Created TRB or NULL\r
215\r
216**/\r
217EFI_STATUS\r
218XhcCreateTransferTrb (\r
219 IN USB_XHCI_INSTANCE *Xhc,\r
220 IN URB *Urb\r
221 )\r
222{\r
223 VOID *OutputContext;\r
224 TRANSFER_RING *EPRing;\r
225 UINT8 EPType;\r
226 UINT8 SlotId;\r
227 UINT8 Dci;\r
228 TRB *TrbStart;\r
229 UINTN TotalLen;\r
230 UINTN Len;\r
231 UINTN TrbNum;\r
232 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
233 EFI_PHYSICAL_ADDRESS PhyAddr;\r
234 VOID *Map;\r
235 EFI_STATUS Status;\r
236\r
237 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
238 if (SlotId == 0) {\r
239 return EFI_DEVICE_ERROR;\r
240 }\r
241\r
242 Urb->Finished = FALSE;\r
243 Urb->StartDone = FALSE;\r
244 Urb->EndDone = FALSE;\r
245 Urb->Completed = 0;\r
246 Urb->Result = EFI_USB_NOERROR;\r
247\r
248 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
249 ASSERT (Dci < 32);\r
250 EPRing = (TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1];\r
251 Urb->Ring = EPRing;\r
252 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
253 if (Xhc->HcCParams.Data.Csz == 0) {\r
254 EPType = (UINT8)((DEVICE_CONTEXT *)OutputContext)->EP[Dci-1].EPType;\r
255 } else {\r
256 EPType = (UINT8)((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
257 }\r
258\r
259 //\r
260 // No need to remap.\r
261 //\r
262 if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {\r
263 if (((UINT8)(Urb->Ep.Direction)) == EfiUsbDataIn) {\r
264 MapOp = EfiPciIoOperationBusMasterWrite;\r
265 } else {\r
266 MapOp = EfiPciIoOperationBusMasterRead;\r
267 }\r
268\r
269 Len = Urb->DataLen;\r
270 Status = Xhc->PciIo->Map (Xhc->PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
271\r
272 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
273 DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));\r
274 return EFI_OUT_OF_RESOURCES;\r
275 }\r
276\r
277 Urb->DataPhy = (VOID *)((UINTN)PhyAddr);\r
278 Urb->DataMap = Map;\r
279 }\r
280\r
281 //\r
282 // Construct the TRB\r
283 //\r
284 XhcSyncTrsRing (Xhc, EPRing);\r
285 Urb->TrbStart = EPRing->RingEnqueue;\r
286 switch (EPType) {\r
287 case ED_CONTROL_BIDIR:\r
288 //\r
289 // For control transfer, create SETUP_STAGE_TRB first.\r
290 //\r
291 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
292 TrbStart->TrbCtrSetup.bmRequestType = Urb->Request->RequestType;\r
293 TrbStart->TrbCtrSetup.bRequest = Urb->Request->Request;\r
294 TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
295 TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
296 TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
297 TrbStart->TrbCtrSetup.Length = 8;\r
298 TrbStart->TrbCtrSetup.IntTarget = 0;\r
299 TrbStart->TrbCtrSetup.IOC = 1;\r
300 TrbStart->TrbCtrSetup.IDT = 1;\r
301 TrbStart->TrbCtrSetup.Type = TRB_TYPE_SETUP_STAGE;\r
302 if (Urb->DataLen > 0) {\r
303 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
304 TrbStart->TrbCtrSetup.TRT = 3;\r
305 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
306 TrbStart->TrbCtrSetup.TRT = 2;\r
307 } else {\r
308 DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Direction sholud be IN or OUT when Data exists!\n"));\r
309 ASSERT (FALSE);\r
310 }\r
311 } else {\r
312 TrbStart->TrbCtrSetup.TRT = 0;\r
313 }\r
314\r
315 //\r
316 // Update the cycle bit\r
317 //\r
318 TrbStart->TrbCtrSetup.CycleBit = EPRing->RingPCS & BIT0;\r
319 Urb->TrbNum++;\r
320\r
321 //\r
322 // For control transfer, create DATA_STAGE_TRB.\r
323 //\r
324 if (Urb->DataLen > 0) {\r
325 XhcSyncTrsRing (Xhc, EPRing);\r
326 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
327 TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT (Urb->DataPhy);\r
328 TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT (Urb->DataPhy);\r
329 TrbStart->TrbCtrData.Length = (UINT32)Urb->DataLen;\r
330 TrbStart->TrbCtrData.TDSize = 0;\r
331 TrbStart->TrbCtrData.IntTarget = 0;\r
332 TrbStart->TrbCtrData.ISP = 1;\r
333 TrbStart->TrbCtrData.IOC = 1;\r
334 TrbStart->TrbCtrData.IDT = 0;\r
335 TrbStart->TrbCtrData.CH = 0;\r
336 TrbStart->TrbCtrData.Type = TRB_TYPE_DATA_STAGE;\r
337 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
338 TrbStart->TrbCtrData.DIR = 1;\r
339 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
340 TrbStart->TrbCtrData.DIR = 0;\r
341 } else {\r
342 TrbStart->TrbCtrData.DIR = 0;\r
343 }\r
344\r
345 //\r
346 // Update the cycle bit\r
347 //\r
348 TrbStart->TrbCtrData.CycleBit = EPRing->RingPCS & BIT0;\r
349 Urb->TrbNum++;\r
350 }\r
351\r
352 //\r
353 // For control transfer, create STATUS_STAGE_TRB.\r
354 // Get the pointer to next TRB for status stage use\r
355 //\r
356 XhcSyncTrsRing (Xhc, EPRing);\r
357 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
358 TrbStart->TrbCtrStatus.IntTarget = 0;\r
359 TrbStart->TrbCtrStatus.IOC = 1;\r
360 TrbStart->TrbCtrStatus.CH = 0;\r
361 TrbStart->TrbCtrStatus.Type = TRB_TYPE_STATUS_STAGE;\r
362 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
363 TrbStart->TrbCtrStatus.DIR = 0;\r
364 } else if (Urb->Ep.Direction == EfiUsbDataOut) {\r
365 TrbStart->TrbCtrStatus.DIR = 1;\r
366 } else {\r
367 TrbStart->TrbCtrStatus.DIR = 0;\r
368 }\r
369\r
370 //\r
371 // Update the cycle bit\r
372 //\r
373 TrbStart->TrbCtrStatus.CycleBit = EPRing->RingPCS & BIT0;\r
374 //\r
375 // Update the enqueue pointer\r
376 //\r
377 XhcSyncTrsRing (Xhc, EPRing);\r
378 Urb->TrbNum++;\r
379 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
380\r
381 break;\r
382\r
383 case ED_BULK_OUT:\r
384 case ED_BULK_IN:\r
385 TotalLen = 0;\r
386 Len = 0;\r
387 TrbNum = 0;\r
388 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
389 while (TotalLen < Urb->DataLen) {\r
390 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
391 Len = Urb->DataLen - TotalLen;\r
392 } else {\r
393 Len = 0x10000;\r
394 }\r
395\r
396 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
397 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
398 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
399 TrbStart->TrbNormal.Length = (UINT32)Len;\r
400 TrbStart->TrbNormal.TDSize = 0;\r
401 TrbStart->TrbNormal.IntTarget = 0;\r
402 TrbStart->TrbNormal.ISP = 1;\r
403 TrbStart->TrbNormal.IOC = 1;\r
404 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
405 //\r
406 // Update the cycle bit\r
407 //\r
408 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
409\r
410 XhcSyncTrsRing (Xhc, EPRing);\r
411 TrbNum++;\r
412 TotalLen += Len;\r
413 }\r
414\r
415 Urb->TrbNum = TrbNum;\r
416 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
417 break;\r
418\r
419 case ED_INTERRUPT_OUT:\r
420 case ED_INTERRUPT_IN:\r
421 TotalLen = 0;\r
422 Len = 0;\r
423 TrbNum = 0;\r
424 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
425 while (TotalLen < Urb->DataLen) {\r
426 if ((TotalLen + 0x10000) >= Urb->DataLen) {\r
427 Len = Urb->DataLen - TotalLen;\r
428 } else {\r
429 Len = 0x10000;\r
430 }\r
431\r
432 TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
433 TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
434 TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT ((UINT8 *)Urb->DataPhy + TotalLen);\r
435 TrbStart->TrbNormal.Length = (UINT32)Len;\r
436 TrbStart->TrbNormal.TDSize = 0;\r
437 TrbStart->TrbNormal.IntTarget = 0;\r
438 TrbStart->TrbNormal.ISP = 1;\r
439 TrbStart->TrbNormal.IOC = 1;\r
440 TrbStart->TrbNormal.Type = TRB_TYPE_NORMAL;\r
441 //\r
442 // Update the cycle bit\r
443 //\r
444 TrbStart->TrbNormal.CycleBit = EPRing->RingPCS & BIT0;\r
445\r
446 XhcSyncTrsRing (Xhc, EPRing);\r
447 TrbNum++;\r
448 TotalLen += Len;\r
449 }\r
450\r
451 Urb->TrbNum = TrbNum;\r
452 Urb->TrbEnd = (TRB_TEMPLATE *)(UINTN)TrbStart;\r
453 break;\r
454\r
455 default:\r
456 DEBUG ((DEBUG_INFO, "Not supported EPType 0x%x!\n", EPType));\r
457 ASSERT (FALSE);\r
458 break;\r
459 }\r
460\r
461 return EFI_SUCCESS;\r
462}\r
463\r
464/**\r
465 Initialize the XHCI host controller for schedule.\r
466\r
467 @param Xhc The XHCI Instance to be initialized.\r
468\r
469**/\r
470VOID\r
471XhcInitSched (\r
472 IN USB_XHCI_INSTANCE *Xhc\r
473 )\r
474{\r
475 VOID *Dcbaa;\r
476 EFI_PHYSICAL_ADDRESS DcbaaPhy;\r
477 UINT64 CmdRing;\r
478 EFI_PHYSICAL_ADDRESS CmdRingPhy;\r
479 UINTN Entries;\r
480 UINT32 MaxScratchpadBufs;\r
481 UINT64 *ScratchBuf;\r
482 EFI_PHYSICAL_ADDRESS ScratchPhy;\r
483 UINT64 *ScratchEntry;\r
484 EFI_PHYSICAL_ADDRESS ScratchEntryPhy;\r
485 UINT32 Index;\r
486 UINTN *ScratchEntryMap;\r
487 EFI_STATUS Status;\r
488\r
489 //\r
490 // Initialize memory management.\r
491 //\r
492 Xhc->MemPool = UsbHcInitMemPool (Xhc->PciIo);\r
493 ASSERT (Xhc->MemPool != NULL);\r
494\r
495 //\r
496 // Program the Max Device Slots Enabled (MaxSlotsEn) field in the CONFIG register (5.4.7)\r
497 // to enable the device slots that system software is going to use.\r
498 //\r
499 Xhc->MaxSlotsEn = Xhc->HcSParams1.Data.MaxSlots;\r
500 ASSERT (Xhc->MaxSlotsEn >= 1 && Xhc->MaxSlotsEn <= 255);\r
501 XhcWriteOpReg (Xhc, XHC_CONFIG_OFFSET, Xhc->MaxSlotsEn);\r
502\r
503 //\r
504 // The Device Context Base Address Array entry associated with each allocated Device Slot\r
505 // shall contain a 64-bit pointer to the base of the associated Device Context.\r
506 // The Device Context Base Address Array shall contain MaxSlotsEn + 1 entries.\r
507 // Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.\r
508 //\r
509 Entries = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);\r
510 Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries, FALSE);\r
511 ASSERT (Dcbaa != NULL);\r
512 ZeroMem (Dcbaa, Entries);\r
513\r
514 //\r
515 // A Scratchpad Buffer is a PAGESIZE block of system memory located on a PAGESIZE boundary.\r
516 // System software shall allocate the Scratchpad Buffer(s) before placing the xHC in to Run\r
517 // mode (Run/Stop(R/S) ='1').\r
518 //\r
519 MaxScratchpadBufs = ((Xhc->HcSParams2.Data.ScratchBufHi) << 5) | (Xhc->HcSParams2.Data.ScratchBufLo);\r
520 Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
521 ASSERT (MaxScratchpadBufs <= 1023);\r
522 if (MaxScratchpadBufs != 0) {\r
523 //\r
524 // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them\r
525 //\r
526 ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);\r
527 ASSERT (ScratchEntryMap != NULL);\r
528 Xhc->ScratchEntryMap = ScratchEntryMap;\r
529\r
530 //\r
531 // Allocate the buffer to record the host address for each entry\r
532 //\r
533 ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);\r
534 ASSERT (ScratchEntry != NULL);\r
535 Xhc->ScratchEntry = ScratchEntry;\r
536\r
537 ScratchPhy = 0;\r
538 Status = UsbHcAllocateAlignedPages (\r
539 Xhc->PciIo,\r
540 EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
541 Xhc->PageSize,\r
542 (VOID **)&ScratchBuf,\r
543 &ScratchPhy,\r
544 &Xhc->ScratchMap\r
545 );\r
546 ASSERT_EFI_ERROR (Status);\r
547\r
548 ZeroMem (ScratchBuf, MaxScratchpadBufs * sizeof (UINT64));\r
549 Xhc->ScratchBuf = ScratchBuf;\r
550\r
551 //\r
552 // Allocate each scratch buffer\r
553 //\r
554 for (Index = 0; Index < MaxScratchpadBufs; Index++) {\r
555 ScratchEntryPhy = 0;\r
556 Status = UsbHcAllocateAlignedPages (\r
557 Xhc->PciIo,\r
558 EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
559 Xhc->PageSize,\r
560 (VOID **)&ScratchEntry[Index],\r
561 &ScratchEntryPhy,\r
562 (VOID **)&ScratchEntryMap[Index]\r
563 );\r
564 ASSERT_EFI_ERROR (Status);\r
565 ZeroMem ((VOID *)(UINTN)ScratchEntry[Index], Xhc->PageSize);\r
566 //\r
567 // Fill with the PCI device address\r
568 //\r
569 *ScratchBuf++ = ScratchEntryPhy;\r
570 }\r
571\r
572 //\r
573 // The Scratchpad Buffer Array contains pointers to the Scratchpad Buffers. Entry 0 of the\r
574 // Device Context Base Address Array points to the Scratchpad Buffer Array.\r
575 //\r
576 *(UINT64 *)Dcbaa = (UINT64)(UINTN)ScratchPhy;\r
577 }\r
578\r
579 //\r
580 // Program the Device Context Base Address Array Pointer (DCBAAP) register (5.4.6) with\r
581 // a 64-bit address pointing to where the Device Context Base Address Array is located.\r
582 //\r
583 Xhc->DCBAA = (UINT64 *)(UINTN)Dcbaa;\r
584 //\r
585 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
586 // So divide it to two 32-bytes width register access.\r
587 //\r
588 DcbaaPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Dcbaa, Entries);\r
589 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET, XHC_LOW_32BIT (DcbaaPhy));\r
590 XhcWriteOpReg (Xhc, XHC_DCBAAP_OFFSET + 4, XHC_HIGH_32BIT (DcbaaPhy));\r
591\r
592 DEBUG ((DEBUG_INFO, "XhcInitSched:DCBAA=0x%x\n", (UINT64)(UINTN)Xhc->DCBAA));\r
593\r
594 //\r
595 // Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register\r
596 // (5.4.5) with a 64-bit address pointing to the starting address of the first TRB of the Command Ring.\r
597 // Note: The Command Ring is 64 byte aligned, so the low order 6 bits of the Command Ring Pointer shall\r
598 // always be '0'.\r
599 //\r
600 CreateTransferRing (Xhc, CMD_RING_TRB_NUMBER, &Xhc->CmdRing);\r
601 //\r
602 // The xHC uses the Enqueue Pointer to determine when a Transfer Ring is empty. As it fetches TRBs from a\r
603 // Transfer Ring it checks for a Cycle bit transition. If a transition detected, the ring is empty.\r
604 // So we set RCS as inverted PCS init value to let Command Ring empty\r
605 //\r
606 CmdRing = (UINT64)(UINTN)Xhc->CmdRing.RingSeg0;\r
607 CmdRingPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, (VOID *)(UINTN)CmdRing, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
608 ASSERT ((CmdRingPhy & 0x3F) == 0);\r
609 CmdRingPhy |= XHC_CRCR_RCS;\r
610 //\r
611 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
612 // So divide it to two 32-bytes width register access.\r
613 //\r
614 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT (CmdRingPhy));\r
615 XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
616\r
617 //\r
618 // Disable the 'interrupter enable' bit in USB_CMD\r
619 // and clear IE & IP bit in all Interrupter X Management Registers.\r
620 //\r
621 XhcClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_INTE);\r
622 for (Index = 0; Index < (UINT16)(Xhc->HcSParams1.Data.MaxIntrs); Index++) {\r
623 XhcClearRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IE);\r
624 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET + (Index * 32), XHC_IMAN_IP);\r
625 }\r
626\r
627 //\r
628 // Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
629 //\r
630 CreateEventRing (Xhc, &Xhc->EventRing);\r
631 DEBUG ((\r
632 DEBUG_INFO,\r
633 "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",\r
634 Xhc->CmdRing.RingSeg0,\r
635 (UINTN)Xhc->CmdRing.RingSeg0 + sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER,\r
636 Xhc->EventRing.EventRingSeg0,\r
637 (UINTN)Xhc->EventRing.EventRingSeg0 + sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER\r
638 ));\r
639}\r
640\r
641/**\r
642 System software shall use a Reset Endpoint Command (section 4.11.4.7) to remove the Halted\r
643 condition in the xHC. After the successful completion of the Reset Endpoint Command, the Endpoint\r
644 Context is transitioned from the Halted to the Stopped state and the Transfer Ring of the endpoint is\r
645 reenabled. The next write to the Doorbell of the Endpoint will transition the Endpoint Context from the\r
646 Stopped to the Running state.\r
647\r
648 @param Xhc The XHCI Instance.\r
649 @param Urb The urb which makes the endpoint halted.\r
650\r
651 @retval EFI_SUCCESS The recovery is successful.\r
652 @retval Others Failed to recovery halted endpoint.\r
653\r
654**/\r
655EFI_STATUS\r
656EFIAPI\r
657XhcRecoverHaltedEndpoint (\r
658 IN USB_XHCI_INSTANCE *Xhc,\r
659 IN URB *Urb\r
660 )\r
661{\r
662 EFI_STATUS Status;\r
663 UINT8 Dci;\r
664 UINT8 SlotId;\r
665\r
666 Status = EFI_SUCCESS;\r
667 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
668 if (SlotId == 0) {\r
669 return EFI_DEVICE_ERROR;\r
670 }\r
671\r
672 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
673 ASSERT (Dci < 32);\r
674\r
675 DEBUG ((DEBUG_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
676\r
677 //\r
678 // 1) Send Reset endpoint command to transit from halt to stop state\r
679 //\r
680 Status = XhcResetEndpoint (Xhc, SlotId, Dci);\r
681 if (EFI_ERROR (Status)) {\r
682 DEBUG ((DEBUG_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
683 goto Done;\r
684 }\r
685\r
686 //\r
687 // 2)Set dequeue pointer\r
688 //\r
689 Status = XhcSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);\r
690 if (EFI_ERROR (Status)) {\r
691 DEBUG ((DEBUG_ERROR, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
692 goto Done;\r
693 }\r
694\r
695 //\r
696 // 3)Ring the doorbell to transit from stop to active\r
697 //\r
698 XhcRingDoorBell (Xhc, SlotId, Dci);\r
699\r
700Done:\r
701 return Status;\r
702}\r
703\r
704/**\r
705 System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
706 Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
707 the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
708 state.\r
709\r
710 @param Xhc The XHCI Instance.\r
711 @param Urb The urb which doesn't get completed in a specified timeout range.\r
712\r
713 @retval EFI_SUCCESS The dequeuing of the TDs is successful.\r
714 @retval EFI_ALREADY_STARTED The Urb is finished so no deque is needed.\r
715 @retval Others Failed to stop the endpoint and dequeue the TDs.\r
716\r
717**/\r
718EFI_STATUS\r
719EFIAPI\r
720XhcDequeueTrbFromEndpoint (\r
721 IN USB_XHCI_INSTANCE *Xhc,\r
722 IN URB *Urb\r
723 )\r
724{\r
725 EFI_STATUS Status;\r
726 UINT8 Dci;\r
727 UINT8 SlotId;\r
728\r
729 Status = EFI_SUCCESS;\r
730 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
731 if (SlotId == 0) {\r
732 return EFI_DEVICE_ERROR;\r
733 }\r
734\r
735 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
736 ASSERT (Dci < 32);\r
737\r
738 DEBUG ((DEBUG_VERBOSE, "Stop Slot = %x,Dci = %x\n", SlotId, Dci));\r
739\r
740 //\r
741 // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint\r
742 //\r
743 Status = XhcStopEndpoint (Xhc, SlotId, Dci, Urb);\r
744 if (EFI_ERROR (Status)) {\r
745 DEBUG ((DEBUG_ERROR, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
746 goto Done;\r
747 }\r
748\r
749 //\r
750 // 2)Set dequeue pointer\r
751 //\r
752 if (Urb->Finished && (Urb->Result == EFI_USB_NOERROR)) {\r
753 //\r
754 // Return Already Started to indicate the pending URB is finished.\r
755 // This fixes BULK data loss when transfer is detected as timeout\r
756 // but finished just before stopping endpoint.\r
757 //\r
758 Status = EFI_ALREADY_STARTED;\r
759 DEBUG ((DEBUG_INFO, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb->Completed, Urb->DataLen));\r
760 } else {\r
761 Status = XhcSetTrDequeuePointer (Xhc, SlotId, Dci, Urb);\r
762 if (EFI_ERROR (Status)) {\r
763 DEBUG ((DEBUG_ERROR, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
764 goto Done;\r
765 }\r
766 }\r
767\r
768 //\r
769 // 3)Ring the doorbell to transit from stop to active\r
770 //\r
771 XhcRingDoorBell (Xhc, SlotId, Dci);\r
772\r
773Done:\r
774 return Status;\r
775}\r
776\r
777/**\r
778 Create XHCI event ring.\r
779\r
780 @param Xhc The XHCI Instance.\r
781 @param EventRing The created event ring.\r
782\r
783**/\r
784VOID\r
785CreateEventRing (\r
786 IN USB_XHCI_INSTANCE *Xhc,\r
787 OUT EVENT_RING *EventRing\r
788 )\r
789{\r
790 VOID *Buf;\r
791 EVENT_RING_SEG_TABLE_ENTRY *ERSTBase;\r
792 UINTN Size;\r
793 EFI_PHYSICAL_ADDRESS ERSTPhy;\r
794 EFI_PHYSICAL_ADDRESS DequeuePhy;\r
795\r
796 ASSERT (EventRing != NULL);\r
797\r
798 Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;\r
799 Buf = UsbHcAllocateMem (Xhc->MemPool, Size, TRUE);\r
800 ASSERT (Buf != NULL);\r
801 ASSERT (((UINTN)Buf & 0x3F) == 0);\r
802 ZeroMem (Buf, Size);\r
803\r
804 EventRing->EventRingSeg0 = Buf;\r
805 EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
806 EventRing->EventRingDequeue = (TRB_TEMPLATE *)EventRing->EventRingSeg0;\r
807 EventRing->EventRingEnqueue = (TRB_TEMPLATE *)EventRing->EventRingSeg0;\r
808\r
809 DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
810\r
811 //\r
812 // Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
813 // and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
814 //\r
815 EventRing->EventRingCCS = 1;\r
816\r
817 Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;\r
818 Buf = UsbHcAllocateMem (Xhc->MemPool, Size, FALSE);\r
819 ASSERT (Buf != NULL);\r
820 ASSERT (((UINTN)Buf & 0x3F) == 0);\r
821 ZeroMem (Buf, Size);\r
822\r
823 ERSTBase = (EVENT_RING_SEG_TABLE_ENTRY *)Buf;\r
824 EventRing->ERSTBase = ERSTBase;\r
825 ERSTBase->PtrLo = XHC_LOW_32BIT (DequeuePhy);\r
826 ERSTBase->PtrHi = XHC_HIGH_32BIT (DequeuePhy);\r
827 ERSTBase->RingTrbSize = EVENT_RING_TRB_NUMBER;\r
828\r
829 ERSTPhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, ERSTBase, Size);\r
830\r
831 //\r
832 // Program the Interrupter Event Ring Segment Table Size (ERSTSZ) register (5.5.2.3.1)\r
833 //\r
834 XhcWriteRuntimeReg (\r
835 Xhc,\r
836 XHC_ERSTSZ_OFFSET,\r
837 ERST_NUMBER\r
838 );\r
839 //\r
840 // Program the Interrupter Event Ring Dequeue Pointer (ERDP) register (5.5.2.3.3)\r
841 //\r
842 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
843 // So divide it to two 32-bytes width register access.\r
844 //\r
845 XhcWriteRuntimeReg (\r
846 Xhc,\r
847 XHC_ERDP_OFFSET,\r
848 XHC_LOW_32BIT ((UINT64)(UINTN)DequeuePhy)\r
849 );\r
850 XhcWriteRuntimeReg (\r
851 Xhc,\r
852 XHC_ERDP_OFFSET + 4,\r
853 XHC_HIGH_32BIT ((UINT64)(UINTN)DequeuePhy)\r
854 );\r
855 //\r
856 // Program the Interrupter Event Ring Segment Table Base Address (ERSTBA) register(5.5.2.3.2)\r
857 //\r
858 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
859 // So divide it to two 32-bytes width register access.\r
860 //\r
861 XhcWriteRuntimeReg (\r
862 Xhc,\r
863 XHC_ERSTBA_OFFSET,\r
864 XHC_LOW_32BIT ((UINT64)(UINTN)ERSTPhy)\r
865 );\r
866 XhcWriteRuntimeReg (\r
867 Xhc,\r
868 XHC_ERSTBA_OFFSET + 4,\r
869 XHC_HIGH_32BIT ((UINT64)(UINTN)ERSTPhy)\r
870 );\r
871 //\r
872 // Need set IMAN IE bit to enble the ring interrupt\r
873 //\r
874 XhcSetRuntimeRegBit (Xhc, XHC_IMAN_OFFSET, XHC_IMAN_IE);\r
875}\r
876\r
877/**\r
878 Create XHCI transfer ring.\r
879\r
880 @param Xhc The XHCI Instance.\r
881 @param TrbNum The number of TRB in the ring.\r
882 @param TransferRing The created transfer ring.\r
883\r
884**/\r
885VOID\r
886CreateTransferRing (\r
887 IN USB_XHCI_INSTANCE *Xhc,\r
888 IN UINTN TrbNum,\r
889 OUT TRANSFER_RING *TransferRing\r
890 )\r
891{\r
892 VOID *Buf;\r
893 LINK_TRB *EndTrb;\r
894 EFI_PHYSICAL_ADDRESS PhyAddr;\r
895\r
896 Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum, TRUE);\r
897 ASSERT (Buf != NULL);\r
898 ASSERT (((UINTN)Buf & 0x3F) == 0);\r
899 ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
900\r
901 TransferRing->RingSeg0 = Buf;\r
902 TransferRing->TrbNumber = TrbNum;\r
903 TransferRing->RingEnqueue = (TRB_TEMPLATE *)TransferRing->RingSeg0;\r
904 TransferRing->RingDequeue = (TRB_TEMPLATE *)TransferRing->RingSeg0;\r
905 TransferRing->RingPCS = 1;\r
906 //\r
907 // 4.9.2 Transfer Ring Management\r
908 // To form a ring (or circular queue) a Link TRB may be inserted at the end of a ring to\r
909 // point to the first TRB in the ring.\r
910 //\r
911 EndTrb = (LINK_TRB *)((UINTN)Buf + sizeof (TRB_TEMPLATE) * (TrbNum - 1));\r
912 EndTrb->Type = TRB_TYPE_LINK;\r
913 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, sizeof (TRB_TEMPLATE) * TrbNum);\r
914 EndTrb->PtrLo = XHC_LOW_32BIT (PhyAddr);\r
915 EndTrb->PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
916 //\r
917 // Toggle Cycle (TC). When set to '1', the xHC shall toggle its interpretation of the Cycle bit.\r
918 //\r
919 EndTrb->TC = 1;\r
920 //\r
921 // Set Cycle bit as other TRB PCS init value\r
922 //\r
923 EndTrb->CycleBit = 0;\r
924}\r
925\r
926/**\r
927 Free XHCI event ring.\r
928\r
929 @param Xhc The XHCI Instance.\r
930 @param EventRing The event ring to be freed.\r
931\r
932**/\r
933EFI_STATUS\r
934EFIAPI\r
935XhcFreeEventRing (\r
936 IN USB_XHCI_INSTANCE *Xhc,\r
937 IN EVENT_RING *EventRing\r
938 )\r
939{\r
940 if (EventRing->EventRingSeg0 == NULL) {\r
941 return EFI_SUCCESS;\r
942 }\r
943\r
944 //\r
945 // Free EventRing Segment 0\r
946 //\r
947 UsbHcFreeMem (Xhc->MemPool, EventRing->EventRingSeg0, sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER);\r
948\r
949 //\r
950 // Free ESRT table\r
951 //\r
952 UsbHcFreeMem (Xhc->MemPool, EventRing->ERSTBase, sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER);\r
953 return EFI_SUCCESS;\r
954}\r
955\r
956/**\r
957 Free the resouce allocated at initializing schedule.\r
958\r
959 @param Xhc The XHCI Instance.\r
960\r
961**/\r
962VOID\r
963XhcFreeSched (\r
964 IN USB_XHCI_INSTANCE *Xhc\r
965 )\r
966{\r
967 UINT32 Index;\r
968 UINT64 *ScratchEntry;\r
969\r
970 if (Xhc->ScratchBuf != NULL) {\r
971 ScratchEntry = Xhc->ScratchEntry;\r
972 for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
973 //\r
974 // Free Scratchpad Buffers\r
975 //\r
976 UsbHcFreeAlignedPages (Xhc->PciIo, (VOID *)(UINTN)ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *)Xhc->ScratchEntryMap[Index]);\r
977 }\r
978\r
979 //\r
980 // Free Scratchpad Buffer Array\r
981 //\r
982 UsbHcFreeAlignedPages (Xhc->PciIo, Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);\r
983 FreePool (Xhc->ScratchEntryMap);\r
984 FreePool (Xhc->ScratchEntry);\r
985 }\r
986\r
987 if (Xhc->CmdRing.RingSeg0 != NULL) {\r
988 UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
989 Xhc->CmdRing.RingSeg0 = NULL;\r
990 }\r
991\r
992 XhcFreeEventRing (Xhc, &Xhc->EventRing);\r
993\r
994 if (Xhc->DCBAA != NULL) {\r
995 UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof (UINT64));\r
996 Xhc->DCBAA = NULL;\r
997 }\r
998\r
999 //\r
1000 // Free memory pool at last\r
1001 //\r
1002 if (Xhc->MemPool != NULL) {\r
1003 UsbHcFreeMemPool (Xhc->MemPool);\r
1004 Xhc->MemPool = NULL;\r
1005 }\r
1006}\r
1007\r
1008/**\r
1009 Check if the Trb is a transaction of the URB.\r
1010\r
1011 @param Xhc The XHCI Instance.\r
1012 @param Trb The TRB to be checked\r
1013 @param Urb The URB to be checked.\r
1014\r
1015 @retval TRUE It is a transaction of the URB.\r
1016 @retval FALSE It is not any transaction of the URB.\r
1017\r
1018**/\r
1019BOOLEAN\r
1020IsTransferRingTrb (\r
1021 IN USB_XHCI_INSTANCE *Xhc,\r
1022 IN TRB_TEMPLATE *Trb,\r
1023 IN URB *Urb\r
1024 )\r
1025{\r
1026 LINK_TRB *LinkTrb;\r
1027 TRB_TEMPLATE *CheckedTrb;\r
1028 UINTN Index;\r
1029 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1030\r
1031 CheckedTrb = Urb->TrbStart;\r
1032 for (Index = 0; Index < Urb->TrbNum; Index++) {\r
1033 if (Trb == CheckedTrb) {\r
1034 return TRUE;\r
1035 }\r
1036\r
1037 CheckedTrb++;\r
1038 //\r
1039 // If the checked TRB is the link TRB at the end of the transfer ring,\r
1040 // recircle it to the head of the ring.\r
1041 //\r
1042 if (CheckedTrb->Type == TRB_TYPE_LINK) {\r
1043 LinkTrb = (LINK_TRB *)CheckedTrb;\r
1044 PhyAddr = (EFI_PHYSICAL_ADDRESS)(LinkTrb->PtrLo | LShiftU64 ((UINT64)LinkTrb->PtrHi, 32));\r
1045 CheckedTrb = (TRB_TEMPLATE *)(UINTN)UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN)PhyAddr, sizeof (TRB_TEMPLATE));\r
1046 ASSERT (CheckedTrb == Urb->Ring->RingSeg0);\r
1047 }\r
1048 }\r
1049\r
1050 return FALSE;\r
1051}\r
1052\r
1053/**\r
1054 Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.\r
1055\r
1056 @param Xhc The XHCI Instance.\r
1057 @param Trb The TRB to be checked.\r
1058 @param Urb The pointer to the matched Urb.\r
1059\r
1060 @retval TRUE The Trb is matched with a transaction of the URBs in the async list.\r
1061 @retval FALSE The Trb is not matched with any URBs in the async list.\r
1062\r
1063**/\r
1064BOOLEAN\r
1065IsAsyncIntTrb (\r
1066 IN USB_XHCI_INSTANCE *Xhc,\r
1067 IN TRB_TEMPLATE *Trb,\r
1068 OUT URB **Urb\r
1069 )\r
1070{\r
1071 LIST_ENTRY *Entry;\r
1072 LIST_ENTRY *Next;\r
1073 URB *CheckedUrb;\r
1074\r
1075 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1076 CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1077 if (IsTransferRingTrb (Xhc, Trb, CheckedUrb)) {\r
1078 *Urb = CheckedUrb;\r
1079 return TRUE;\r
1080 }\r
1081 }\r
1082\r
1083 return FALSE;\r
1084}\r
1085\r
1086/**\r
1087 Check the URB's execution result and update the URB's\r
1088 result accordingly.\r
1089\r
1090 @param Xhc The XHCI Instance.\r
1091 @param Urb The URB to check result.\r
1092\r
1093 @return Whether the result of URB transfer is finialized.\r
1094\r
1095**/\r
1096BOOLEAN\r
1097XhcCheckUrbResult (\r
1098 IN USB_XHCI_INSTANCE *Xhc,\r
1099 IN URB *Urb\r
1100 )\r
1101{\r
1102 EVT_TRB_TRANSFER *EvtTrb;\r
1103 TRB_TEMPLATE *TRBPtr;\r
1104 UINTN Index;\r
1105 UINT8 TRBType;\r
1106 EFI_STATUS Status;\r
1107 URB *AsyncUrb;\r
1108 URB *CheckedUrb;\r
1109 UINT64 XhcDequeue;\r
1110 UINT32 High;\r
1111 UINT32 Low;\r
1112 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1113\r
1114 ASSERT ((Xhc != NULL) && (Urb != NULL));\r
1115\r
1116 Status = EFI_SUCCESS;\r
1117 AsyncUrb = NULL;\r
1118\r
1119 if (Urb->Finished) {\r
1120 goto EXIT;\r
1121 }\r
1122\r
1123 EvtTrb = NULL;\r
1124\r
1125 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
1126 Urb->Result |= EFI_USB_ERR_SYSTEM;\r
1127 goto EXIT;\r
1128 }\r
1129\r
1130 //\r
1131 // Traverse the event ring to find out all new events from the previous check.\r
1132 //\r
1133 XhcSyncEventRing (Xhc, &Xhc->EventRing);\r
1134 for (Index = 0; Index < Xhc->EventRing.TrbNumber; Index++) {\r
1135 Status = XhcCheckNewEvent (Xhc, &Xhc->EventRing, ((TRB_TEMPLATE **)&EvtTrb));\r
1136 if (Status == EFI_NOT_READY) {\r
1137 //\r
1138 // All new events are handled, return directly.\r
1139 //\r
1140 goto EXIT;\r
1141 }\r
1142\r
1143 //\r
1144 // Only handle COMMAND_COMPLETETION_EVENT and TRANSFER_EVENT.\r
1145 //\r
1146 if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
1147 continue;\r
1148 }\r
1149\r
1150 //\r
1151 // Need convert pci device address to host address\r
1152 //\r
1153 PhyAddr = (EFI_PHYSICAL_ADDRESS)(EvtTrb->TRBPtrLo | LShiftU64 ((UINT64)EvtTrb->TRBPtrHi, 32));\r
1154 TRBPtr = (TRB_TEMPLATE *)(UINTN)UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN)PhyAddr, sizeof (TRB_TEMPLATE));\r
1155\r
1156 //\r
1157 // Update the status of URB including the pending URB, the URB that is currently checked,\r
1158 // and URBs in the XHCI's async interrupt transfer list.\r
1159 // This way is used to avoid that those completed async transfer events don't get\r
1160 // handled in time and are flushed by newer coming events.\r
1161 //\r
1162 if ((Xhc->PendingUrb != NULL) && IsTransferRingTrb (Xhc, TRBPtr, Xhc->PendingUrb)) {\r
1163 CheckedUrb = Xhc->PendingUrb;\r
1164 } else if (IsTransferRingTrb (Xhc, TRBPtr, Urb)) {\r
1165 CheckedUrb = Urb;\r
1166 } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {\r
1167 CheckedUrb = AsyncUrb;\r
1168 } else {\r
1169 continue;\r
1170 }\r
1171\r
1172 switch (EvtTrb->Completecode) {\r
1173 case TRB_COMPLETION_STALL_ERROR:\r
1174 CheckedUrb->Result |= EFI_USB_ERR_STALL;\r
1175 CheckedUrb->Finished = TRUE;\r
1176 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: STALL_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
1177 goto EXIT;\r
1178\r
1179 case TRB_COMPLETION_BABBLE_ERROR:\r
1180 CheckedUrb->Result |= EFI_USB_ERR_BABBLE;\r
1181 CheckedUrb->Finished = TRUE;\r
1182 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: BABBLE_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
1183 goto EXIT;\r
1184\r
1185 case TRB_COMPLETION_DATA_BUFFER_ERROR:\r
1186 CheckedUrb->Result |= EFI_USB_ERR_BUFFER;\r
1187 CheckedUrb->Finished = TRUE;\r
1188 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));\r
1189 goto EXIT;\r
1190\r
1191 case TRB_COMPLETION_USB_TRANSACTION_ERROR:\r
1192 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1193 CheckedUrb->Finished = TRUE;\r
1194 DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));\r
1195 goto EXIT;\r
1196\r
1197 case TRB_COMPLETION_STOPPED:\r
1198 case TRB_COMPLETION_STOPPED_LENGTH_INVALID:\r
1199 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1200 CheckedUrb->Finished = TRUE;\r
1201 //\r
1202 // The pending URB is timeout and force stopped when stopping endpoint.\r
1203 // Continue the loop to receive the Command Complete Event for stopping endpoint.\r
1204 //\r
1205 continue;\r
1206\r
1207 case TRB_COMPLETION_SHORT_PACKET:\r
1208 case TRB_COMPLETION_SUCCESS:\r
1209 if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
1210 DEBUG ((DEBUG_VERBOSE, "XhcCheckUrbResult: short packet happens!\n"));\r
1211 }\r
1212\r
1213 TRBType = (UINT8)(TRBPtr->Type);\r
1214 if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
1215 (TRBType == TRB_TYPE_NORMAL) ||\r
1216 (TRBType == TRB_TYPE_ISOCH))\r
1217 {\r
1218 CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL *)TRBPtr)->Length - EvtTrb->Length);\r
1219 }\r
1220\r
1221 break;\r
1222\r
1223 default:\r
1224 DEBUG ((DEBUG_ERROR, "Transfer Default Error Occur! Completecode = 0x%x!\n", EvtTrb->Completecode));\r
1225 CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
1226 CheckedUrb->Finished = TRUE;\r
1227 goto EXIT;\r
1228 }\r
1229\r
1230 //\r
1231 // Only check first and end Trb event address\r
1232 //\r
1233 if (TRBPtr == CheckedUrb->TrbStart) {\r
1234 CheckedUrb->StartDone = TRUE;\r
1235 }\r
1236\r
1237 if (TRBPtr == CheckedUrb->TrbEnd) {\r
1238 CheckedUrb->EndDone = TRUE;\r
1239 }\r
1240\r
1241 if (CheckedUrb->StartDone && CheckedUrb->EndDone) {\r
1242 CheckedUrb->Finished = TRUE;\r
1243 CheckedUrb->EvtTrb = (TRB_TEMPLATE *)EvtTrb;\r
1244 }\r
1245 }\r
1246\r
1247EXIT:\r
1248\r
1249 //\r
1250 // Advance event ring to last available entry\r
1251 //\r
1252 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1253 // So divide it to two 32-bytes width register access.\r
1254 //\r
1255 Low = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET);\r
1256 High = XhcReadRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4);\r
1257 XhcDequeue = (UINT64)(LShiftU64 ((UINT64)High, 32) | Low);\r
1258\r
1259 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->EventRing.EventRingDequeue, sizeof (TRB_TEMPLATE));\r
1260\r
1261 if ((XhcDequeue & (~0x0F)) != (PhyAddr & (~0x0F))) {\r
1262 //\r
1263 // Some 3rd party XHCI external cards don't support single 64-bytes width register access,\r
1264 // So divide it to two 32-bytes width register access.\r
1265 //\r
1266 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET, XHC_LOW_32BIT (PhyAddr) | BIT3);\r
1267 XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
1268 }\r
1269\r
1270 return Urb->Finished;\r
1271}\r
1272\r
1273/**\r
1274 Execute the transfer by polling the URB. This is a synchronous operation.\r
1275\r
1276 @param Xhc The XHCI Instance.\r
1277 @param CmdTransfer The executed URB is for cmd transfer or not.\r
1278 @param Urb The URB to execute.\r
1279 @param Timeout The time to wait before abort, in millisecond.\r
1280\r
1281 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.\r
1282 @return EFI_TIMEOUT The transfer failed due to time out.\r
1283 @return EFI_SUCCESS The transfer finished OK.\r
1284 @retval EFI_OUT_OF_RESOURCES Memory for the timer event could not be allocated.\r
1285\r
1286**/\r
1287EFI_STATUS\r
1288XhcExecTransfer (\r
1289 IN USB_XHCI_INSTANCE *Xhc,\r
1290 IN BOOLEAN CmdTransfer,\r
1291 IN URB *Urb,\r
1292 IN UINTN Timeout\r
1293 )\r
1294{\r
1295 EFI_STATUS Status;\r
1296 UINT8 SlotId;\r
1297 UINT8 Dci;\r
1298 BOOLEAN Finished;\r
1299 EFI_EVENT TimeoutEvent;\r
1300 BOOLEAN IndefiniteTimeout;\r
1301\r
1302 Status = EFI_SUCCESS;\r
1303 Finished = FALSE;\r
1304 TimeoutEvent = NULL;\r
1305 IndefiniteTimeout = FALSE;\r
1306\r
1307 if (CmdTransfer) {\r
1308 SlotId = 0;\r
1309 Dci = 0;\r
1310 } else {\r
1311 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1312 if (SlotId == 0) {\r
1313 return EFI_DEVICE_ERROR;\r
1314 }\r
1315\r
1316 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
1317 ASSERT (Dci < 32);\r
1318 }\r
1319\r
1320 if (Timeout == 0) {\r
1321 IndefiniteTimeout = TRUE;\r
1322 goto RINGDOORBELL;\r
1323 }\r
1324\r
1325 Status = gBS->CreateEvent (\r
1326 EVT_TIMER,\r
1327 TPL_CALLBACK,\r
1328 NULL,\r
1329 NULL,\r
1330 &TimeoutEvent\r
1331 );\r
1332\r
1333 if (EFI_ERROR (Status)) {\r
1334 goto DONE;\r
1335 }\r
1336\r
1337 Status = gBS->SetTimer (\r
1338 TimeoutEvent,\r
1339 TimerRelative,\r
1340 EFI_TIMER_PERIOD_MILLISECONDS (Timeout)\r
1341 );\r
1342\r
1343 if (EFI_ERROR (Status)) {\r
1344 goto DONE;\r
1345 }\r
1346\r
1347RINGDOORBELL:\r
1348 XhcRingDoorBell (Xhc, SlotId, Dci);\r
1349\r
1350 do {\r
1351 Finished = XhcCheckUrbResult (Xhc, Urb);\r
1352 if (Finished) {\r
1353 break;\r
1354 }\r
1355\r
1356 gBS->Stall (XHC_1_MICROSECOND);\r
1357 } while (IndefiniteTimeout || EFI_ERROR (gBS->CheckEvent (TimeoutEvent)));\r
1358\r
1359DONE:\r
1360 if (EFI_ERROR (Status)) {\r
1361 Urb->Result = EFI_USB_ERR_NOTEXECUTE;\r
1362 } else if (!Finished) {\r
1363 Urb->Result = EFI_USB_ERR_TIMEOUT;\r
1364 Status = EFI_TIMEOUT;\r
1365 } else if (Urb->Result != EFI_USB_NOERROR) {\r
1366 Status = EFI_DEVICE_ERROR;\r
1367 }\r
1368\r
1369 if (TimeoutEvent != NULL) {\r
1370 gBS->CloseEvent (TimeoutEvent);\r
1371 }\r
1372\r
1373 return Status;\r
1374}\r
1375\r
1376/**\r
1377 Delete a single asynchronous interrupt transfer for\r
1378 the device and endpoint.\r
1379\r
1380 @param Xhc The XHCI Instance.\r
1381 @param BusAddr The logical device address assigned by UsbBus driver.\r
1382 @param EpNum The endpoint of the target.\r
1383\r
1384 @retval EFI_SUCCESS An asynchronous transfer is removed.\r
1385 @retval EFI_NOT_FOUND No transfer for the device is found.\r
1386\r
1387**/\r
1388EFI_STATUS\r
1389XhciDelAsyncIntTransfer (\r
1390 IN USB_XHCI_INSTANCE *Xhc,\r
1391 IN UINT8 BusAddr,\r
1392 IN UINT8 EpNum\r
1393 )\r
1394{\r
1395 LIST_ENTRY *Entry;\r
1396 LIST_ENTRY *Next;\r
1397 URB *Urb;\r
1398 EFI_USB_DATA_DIRECTION Direction;\r
1399 EFI_STATUS Status;\r
1400\r
1401 Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
1402 EpNum &= 0x0F;\r
1403\r
1404 Urb = NULL;\r
1405\r
1406 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1407 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1408 if ((Urb->Ep.BusAddr == BusAddr) &&\r
1409 (Urb->Ep.EpAddr == EpNum) &&\r
1410 (Urb->Ep.Direction == Direction))\r
1411 {\r
1412 //\r
1413 // Device doesn't finish the IntTransfer until real data comes\r
1414 // So the TRB should be removed as well.\r
1415 //\r
1416 Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);\r
1417 if (EFI_ERROR (Status)) {\r
1418 DEBUG ((DEBUG_ERROR, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
1419 }\r
1420\r
1421 RemoveEntryList (&Urb->UrbList);\r
1422 FreePool (Urb->Data);\r
1423 XhcFreeUrb (Xhc, Urb);\r
1424 return EFI_SUCCESS;\r
1425 }\r
1426 }\r
1427\r
1428 return EFI_NOT_FOUND;\r
1429}\r
1430\r
1431/**\r
1432 Remove all the asynchronous interrutp transfers.\r
1433\r
1434 @param Xhc The XHCI Instance.\r
1435\r
1436**/\r
1437VOID\r
1438XhciDelAllAsyncIntTransfers (\r
1439 IN USB_XHCI_INSTANCE *Xhc\r
1440 )\r
1441{\r
1442 LIST_ENTRY *Entry;\r
1443 LIST_ENTRY *Next;\r
1444 URB *Urb;\r
1445 EFI_STATUS Status;\r
1446\r
1447 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1448 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1449\r
1450 //\r
1451 // Device doesn't finish the IntTransfer until real data comes\r
1452 // So the TRB should be removed as well.\r
1453 //\r
1454 Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);\r
1455 if (EFI_ERROR (Status)) {\r
1456 DEBUG ((DEBUG_ERROR, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));\r
1457 }\r
1458\r
1459 RemoveEntryList (&Urb->UrbList);\r
1460 FreePool (Urb->Data);\r
1461 XhcFreeUrb (Xhc, Urb);\r
1462 }\r
1463}\r
1464\r
1465/**\r
1466 Insert a single asynchronous interrupt transfer for\r
1467 the device and endpoint.\r
1468\r
1469 @param Xhc The XHCI Instance\r
1470 @param BusAddr The logical device address assigned by UsbBus driver\r
1471 @param EpAddr Endpoint addrress\r
1472 @param DevSpeed The device speed\r
1473 @param MaxPacket The max packet length of the endpoint\r
1474 @param DataLen The length of data buffer\r
1475 @param Callback The function to call when data is transferred\r
1476 @param Context The context to the callback\r
1477\r
1478 @return Created URB or NULL\r
1479\r
1480**/\r
1481URB *\r
1482XhciInsertAsyncIntTransfer (\r
1483 IN USB_XHCI_INSTANCE *Xhc,\r
1484 IN UINT8 BusAddr,\r
1485 IN UINT8 EpAddr,\r
1486 IN UINT8 DevSpeed,\r
1487 IN UINTN MaxPacket,\r
1488 IN UINTN DataLen,\r
1489 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
1490 IN VOID *Context\r
1491 )\r
1492{\r
1493 VOID *Data;\r
1494 URB *Urb;\r
1495\r
1496 Data = AllocateZeroPool (DataLen);\r
1497 if (Data == NULL) {\r
1498 DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __FUNCTION__));\r
1499 return NULL;\r
1500 }\r
1501\r
1502 Urb = XhcCreateUrb (\r
1503 Xhc,\r
1504 BusAddr,\r
1505 EpAddr,\r
1506 DevSpeed,\r
1507 MaxPacket,\r
1508 XHC_INT_TRANSFER_ASYNC,\r
1509 NULL,\r
1510 Data,\r
1511 DataLen,\r
1512 Callback,\r
1513 Context\r
1514 );\r
1515 if (Urb == NULL) {\r
1516 DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __FUNCTION__));\r
1517 FreePool (Data);\r
1518 return NULL;\r
1519 }\r
1520\r
1521 //\r
1522 // New asynchronous transfer must inserted to the head.\r
1523 // Check the comments in XhcMoniteAsyncRequests\r
1524 //\r
1525 InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);\r
1526\r
1527 return Urb;\r
1528}\r
1529\r
1530/**\r
1531 Update the queue head for next round of asynchronous transfer\r
1532\r
1533 @param Xhc The XHCI Instance.\r
1534 @param Urb The URB to update\r
1535\r
1536**/\r
1537VOID\r
1538XhcUpdateAsyncRequest (\r
1539 IN USB_XHCI_INSTANCE *Xhc,\r
1540 IN URB *Urb\r
1541 )\r
1542{\r
1543 EFI_STATUS Status;\r
1544\r
1545 if (Urb->Result == EFI_USB_NOERROR) {\r
1546 Status = XhcCreateTransferTrb (Xhc, Urb);\r
1547 if (EFI_ERROR (Status)) {\r
1548 return;\r
1549 }\r
1550\r
1551 Status = RingIntTransferDoorBell (Xhc, Urb);\r
1552 if (EFI_ERROR (Status)) {\r
1553 return;\r
1554 }\r
1555 }\r
1556}\r
1557\r
1558/**\r
1559 Flush data from PCI controller specific address to mapped system\r
1560 memory address.\r
1561\r
1562 @param Xhc The XHCI device.\r
1563 @param Urb The URB to unmap.\r
1564\r
1565 @retval EFI_SUCCESS Success to flush data to mapped system memory.\r
1566 @retval EFI_DEVICE_ERROR Fail to flush data to mapped system memory.\r
1567\r
1568**/\r
1569EFI_STATUS\r
1570XhcFlushAsyncIntMap (\r
1571 IN USB_XHCI_INSTANCE *Xhc,\r
1572 IN URB *Urb\r
1573 )\r
1574{\r
1575 EFI_STATUS Status;\r
1576 EFI_PHYSICAL_ADDRESS PhyAddr;\r
1577 EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
1578 EFI_PCI_IO_PROTOCOL *PciIo;\r
1579 UINTN Len;\r
1580 VOID *Map;\r
1581\r
1582 PciIo = Xhc->PciIo;\r
1583 Len = Urb->DataLen;\r
1584\r
1585 if (Urb->Ep.Direction == EfiUsbDataIn) {\r
1586 MapOp = EfiPciIoOperationBusMasterWrite;\r
1587 } else {\r
1588 MapOp = EfiPciIoOperationBusMasterRead;\r
1589 }\r
1590\r
1591 if (Urb->DataMap != NULL) {\r
1592 Status = PciIo->Unmap (PciIo, Urb->DataMap);\r
1593 if (EFI_ERROR (Status)) {\r
1594 goto ON_ERROR;\r
1595 }\r
1596 }\r
1597\r
1598 Urb->DataMap = NULL;\r
1599\r
1600 Status = PciIo->Map (PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
1601 if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
1602 goto ON_ERROR;\r
1603 }\r
1604\r
1605 Urb->DataPhy = (VOID *)((UINTN)PhyAddr);\r
1606 Urb->DataMap = Map;\r
1607 return EFI_SUCCESS;\r
1608\r
1609ON_ERROR:\r
1610 return EFI_DEVICE_ERROR;\r
1611}\r
1612\r
1613/**\r
1614 Interrupt transfer periodic check handler.\r
1615\r
1616 @param Event Interrupt event.\r
1617 @param Context Pointer to USB_XHCI_INSTANCE.\r
1618\r
1619**/\r
1620VOID\r
1621EFIAPI\r
1622XhcMonitorAsyncRequests (\r
1623 IN EFI_EVENT Event,\r
1624 IN VOID *Context\r
1625 )\r
1626{\r
1627 USB_XHCI_INSTANCE *Xhc;\r
1628 LIST_ENTRY *Entry;\r
1629 LIST_ENTRY *Next;\r
1630 UINT8 *ProcBuf;\r
1631 URB *Urb;\r
1632 UINT8 SlotId;\r
1633 EFI_STATUS Status;\r
1634 EFI_TPL OldTpl;\r
1635\r
1636 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1637\r
1638 Xhc = (USB_XHCI_INSTANCE *)Context;\r
1639\r
1640 BASE_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
1641 Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
1642\r
1643 //\r
1644 // Make sure that the device is available before every check.\r
1645 //\r
1646 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
1647 if (SlotId == 0) {\r
1648 continue;\r
1649 }\r
1650\r
1651 //\r
1652 // Check the result of URB execution. If it is still\r
1653 // active, check the next one.\r
1654 //\r
1655 XhcCheckUrbResult (Xhc, Urb);\r
1656\r
1657 if (!Urb->Finished) {\r
1658 continue;\r
1659 }\r
1660\r
1661 //\r
1662 // Flush any PCI posted write transactions from a PCI host\r
1663 // bridge to system memory.\r
1664 //\r
1665 Status = XhcFlushAsyncIntMap (Xhc, Urb);\r
1666 if (EFI_ERROR (Status)) {\r
1667 DEBUG ((DEBUG_ERROR, "XhcMonitorAsyncRequests: Fail to Flush AsyncInt Mapped Memeory\n"));\r
1668 }\r
1669\r
1670 //\r
1671 // Allocate a buffer then copy the transferred data for user.\r
1672 // If failed to allocate the buffer, update the URB for next\r
1673 // round of transfer. Ignore the data of this round.\r
1674 //\r
1675 ProcBuf = NULL;\r
1676 if (Urb->Result == EFI_USB_NOERROR) {\r
1677 //\r
1678 // Make sure the data received from HW is no more than expected.\r
1679 //\r
1680 if (Urb->Completed <= Urb->DataLen) {\r
1681 ProcBuf = AllocateZeroPool (Urb->Completed);\r
1682 }\r
1683\r
1684 if (ProcBuf == NULL) {\r
1685 XhcUpdateAsyncRequest (Xhc, Urb);\r
1686 continue;\r
1687 }\r
1688\r
1689 CopyMem (ProcBuf, Urb->Data, Urb->Completed);\r
1690 }\r
1691\r
1692 //\r
1693 // Leave error recovery to its related device driver. A\r
1694 // common case of the error recovery is to re-submit the\r
1695 // interrupt transfer which is linked to the head of the\r
1696 // list. This function scans from head to tail. So the\r
1697 // re-submitted interrupt transfer's callback function\r
1698 // will not be called again in this round. Don't touch this\r
1699 // URB after the callback, it may have been removed by the\r
1700 // callback.\r
1701 //\r
1702 if (Urb->Callback != NULL) {\r
1703 //\r
1704 // Restore the old TPL, USB bus maybe connect device in\r
1705 // his callback. Some drivers may has a lower TPL restriction.\r
1706 //\r
1707 gBS->RestoreTPL (OldTpl);\r
1708 (Urb->Callback)(ProcBuf, Urb->Completed, Urb->Context, Urb->Result);\r
1709 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1710 }\r
1711\r
1712 if (ProcBuf != NULL) {\r
1713 gBS->FreePool (ProcBuf);\r
1714 }\r
1715\r
1716 XhcUpdateAsyncRequest (Xhc, Urb);\r
1717 }\r
1718 gBS->RestoreTPL (OldTpl);\r
1719}\r
1720\r
1721/**\r
1722 Monitor the port status change. Enable/Disable device slot if there is a device attached/detached.\r
1723\r
1724 @param Xhc The XHCI Instance.\r
1725 @param ParentRouteChart The route string pointed to the parent device if it exists.\r
1726 @param Port The port to be polled.\r
1727 @param PortState The port state.\r
1728\r
1729 @retval EFI_SUCCESS Successfully enable/disable device slot according to port state.\r
1730 @retval Others Should not appear.\r
1731\r
1732**/\r
1733EFI_STATUS\r
1734EFIAPI\r
1735XhcPollPortStatusChange (\r
1736 IN USB_XHCI_INSTANCE *Xhc,\r
1737 IN USB_DEV_ROUTE ParentRouteChart,\r
1738 IN UINT8 Port,\r
1739 IN EFI_USB_PORT_STATUS *PortState\r
1740 )\r
1741{\r
1742 EFI_STATUS Status;\r
1743 UINT8 Speed;\r
1744 UINT8 SlotId;\r
1745 UINT8 Retries;\r
1746 USB_DEV_ROUTE RouteChart;\r
1747\r
1748 Status = EFI_SUCCESS;\r
1749 Retries = XHC_INIT_DEVICE_SLOT_RETRIES;\r
1750\r
1751 if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {\r
1752 return EFI_SUCCESS;\r
1753 }\r
1754\r
1755 if (ParentRouteChart.Dword == 0) {\r
1756 RouteChart.Route.RouteString = 0;\r
1757 RouteChart.Route.RootPortNum = Port + 1;\r
1758 RouteChart.Route.TierNum = 1;\r
1759 } else {\r
1760 if (Port < 14) {\r
1761 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (Port << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
1762 } else {\r
1763 RouteChart.Route.RouteString = ParentRouteChart.Route.RouteString | (15 << (4 * (ParentRouteChart.Route.TierNum - 1)));\r
1764 }\r
1765\r
1766 RouteChart.Route.RootPortNum = ParentRouteChart.Route.RootPortNum;\r
1767 RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;\r
1768 }\r
1769\r
1770 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1771 if (SlotId != 0) {\r
1772 if (Xhc->HcCParams.Data.Csz == 0) {\r
1773 Status = XhcDisableSlotCmd (Xhc, SlotId);\r
1774 } else {\r
1775 Status = XhcDisableSlotCmd64 (Xhc, SlotId);\r
1776 }\r
1777 }\r
1778\r
1779 if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&\r
1780 ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0))\r
1781 {\r
1782 //\r
1783 // Has a device attached, Identify device speed after port is enabled.\r
1784 //\r
1785 Speed = EFI_USB_SPEED_FULL;\r
1786 if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {\r
1787 Speed = EFI_USB_SPEED_LOW;\r
1788 } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {\r
1789 Speed = EFI_USB_SPEED_HIGH;\r
1790 } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {\r
1791 Speed = EFI_USB_SPEED_SUPER;\r
1792 }\r
1793\r
1794 do {\r
1795 //\r
1796 // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.\r
1797 //\r
1798 SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);\r
1799 if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {\r
1800 if (Xhc->HcCParams.Data.Csz == 0) {\r
1801 Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1802 } else {\r
1803 Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
1804 }\r
1805 }\r
1806\r
1807 //\r
1808 // According to the xHCI specification (section 4.6.5), "a USB Transaction\r
1809 // Error Completion Code for an Address Device Command may be due to a Stall\r
1810 // response from a device. Software should issue a Disable Slot Command for\r
1811 // the Device Slot then an Enable Slot Command to recover from this error."\r
1812 // Therefore, retry the device slot initialization if it fails due to a\r
1813 // device error.\r
1814 //\r
1815 } while ((Status == EFI_DEVICE_ERROR) && (Retries-- != 0));\r
1816 }\r
1817\r
1818 return Status;\r
1819}\r
1820\r
1821/**\r
1822 Calculate the device context index by endpoint address and direction.\r
1823\r
1824 @param EpAddr The target endpoint number.\r
1825 @param Direction The direction of the target endpoint.\r
1826\r
1827 @return The device context index of endpoint.\r
1828\r
1829**/\r
1830UINT8\r
1831XhcEndpointToDci (\r
1832 IN UINT8 EpAddr,\r
1833 IN UINT8 Direction\r
1834 )\r
1835{\r
1836 UINT8 Index;\r
1837\r
1838 if (EpAddr == 0) {\r
1839 return 1;\r
1840 } else {\r
1841 Index = (UINT8)(2 * EpAddr);\r
1842 if (Direction == EfiUsbDataIn) {\r
1843 Index += 1;\r
1844 }\r
1845\r
1846 return Index;\r
1847 }\r
1848}\r
1849\r
1850/**\r
1851 Find out the actual device address according to the requested device address from UsbBus.\r
1852\r
1853 @param Xhc The XHCI Instance.\r
1854 @param BusDevAddr The requested device address by UsbBus upper driver.\r
1855\r
1856 @return The actual device address assigned to the device.\r
1857\r
1858**/\r
1859UINT8\r
1860EFIAPI\r
1861XhcBusDevAddrToSlotId (\r
1862 IN USB_XHCI_INSTANCE *Xhc,\r
1863 IN UINT8 BusDevAddr\r
1864 )\r
1865{\r
1866 UINT8 Index;\r
1867\r
1868 for (Index = 0; Index < 255; Index++) {\r
1869 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1870 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1871 (Xhc->UsbDevContext[Index + 1].BusDevAddr == BusDevAddr))\r
1872 {\r
1873 break;\r
1874 }\r
1875 }\r
1876\r
1877 if (Index == 255) {\r
1878 return 0;\r
1879 }\r
1880\r
1881 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1882}\r
1883\r
1884/**\r
1885 Find out the slot id according to the device's route string.\r
1886\r
1887 @param Xhc The XHCI Instance.\r
1888 @param RouteString The route string described the device location.\r
1889\r
1890 @return The slot id used by the device.\r
1891\r
1892**/\r
1893UINT8\r
1894EFIAPI\r
1895XhcRouteStringToSlotId (\r
1896 IN USB_XHCI_INSTANCE *Xhc,\r
1897 IN USB_DEV_ROUTE RouteString\r
1898 )\r
1899{\r
1900 UINT8 Index;\r
1901\r
1902 for (Index = 0; Index < 255; Index++) {\r
1903 if (Xhc->UsbDevContext[Index + 1].Enabled &&\r
1904 (Xhc->UsbDevContext[Index + 1].SlotId != 0) &&\r
1905 (Xhc->UsbDevContext[Index + 1].RouteString.Dword == RouteString.Dword))\r
1906 {\r
1907 break;\r
1908 }\r
1909 }\r
1910\r
1911 if (Index == 255) {\r
1912 return 0;\r
1913 }\r
1914\r
1915 return Xhc->UsbDevContext[Index + 1].SlotId;\r
1916}\r
1917\r
1918/**\r
1919 Synchronize the specified event ring to update the enqueue and dequeue pointer.\r
1920\r
1921 @param Xhc The XHCI Instance.\r
1922 @param EvtRing The event ring to sync.\r
1923\r
1924 @retval EFI_SUCCESS The event ring is synchronized successfully.\r
1925\r
1926**/\r
1927EFI_STATUS\r
1928EFIAPI\r
1929XhcSyncEventRing (\r
1930 IN USB_XHCI_INSTANCE *Xhc,\r
1931 IN EVENT_RING *EvtRing\r
1932 )\r
1933{\r
1934 UINTN Index;\r
1935 TRB_TEMPLATE *EvtTrb1;\r
1936\r
1937 ASSERT (EvtRing != NULL);\r
1938\r
1939 //\r
1940 // Calculate the EventRingEnqueue and EventRingCCS.\r
1941 // Note: only support single Segment\r
1942 //\r
1943 EvtTrb1 = EvtRing->EventRingDequeue;\r
1944\r
1945 for (Index = 0; Index < EvtRing->TrbNumber; Index++) {\r
1946 if (EvtTrb1->CycleBit != EvtRing->EventRingCCS) {\r
1947 break;\r
1948 }\r
1949\r
1950 EvtTrb1++;\r
1951\r
1952 if ((UINTN)EvtTrb1 >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
1953 EvtTrb1 = EvtRing->EventRingSeg0;\r
1954 EvtRing->EventRingCCS = (EvtRing->EventRingCCS) ? 0 : 1;\r
1955 }\r
1956 }\r
1957\r
1958 if (Index < EvtRing->TrbNumber) {\r
1959 EvtRing->EventRingEnqueue = EvtTrb1;\r
1960 } else {\r
1961 ASSERT (FALSE);\r
1962 }\r
1963\r
1964 return EFI_SUCCESS;\r
1965}\r
1966\r
1967/**\r
1968 Synchronize the specified transfer ring to update the enqueue and dequeue pointer.\r
1969\r
1970 @param Xhc The XHCI Instance.\r
1971 @param TrsRing The transfer ring to sync.\r
1972\r
1973 @retval EFI_SUCCESS The transfer ring is synchronized successfully.\r
1974\r
1975**/\r
1976EFI_STATUS\r
1977EFIAPI\r
1978XhcSyncTrsRing (\r
1979 IN USB_XHCI_INSTANCE *Xhc,\r
1980 IN TRANSFER_RING *TrsRing\r
1981 )\r
1982{\r
1983 UINTN Index;\r
1984 TRB_TEMPLATE *TrsTrb;\r
1985\r
1986 ASSERT (TrsRing != NULL);\r
1987 //\r
1988 // Calculate the latest RingEnqueue and RingPCS\r
1989 //\r
1990 TrsTrb = TrsRing->RingEnqueue;\r
1991 ASSERT (TrsTrb != NULL);\r
1992\r
1993 for (Index = 0; Index < TrsRing->TrbNumber; Index++) {\r
1994 if (TrsTrb->CycleBit != (TrsRing->RingPCS & BIT0)) {\r
1995 break;\r
1996 }\r
1997\r
1998 TrsTrb++;\r
1999 if ((UINT8)TrsTrb->Type == TRB_TYPE_LINK) {\r
2000 ASSERT (((LINK_TRB *)TrsTrb)->TC != 0);\r
2001 //\r
2002 // set cycle bit in Link TRB as normal\r
2003 //\r
2004 ((LINK_TRB *)TrsTrb)->CycleBit = TrsRing->RingPCS & BIT0;\r
2005 //\r
2006 // Toggle PCS maintained by software\r
2007 //\r
2008 TrsRing->RingPCS = (TrsRing->RingPCS & BIT0) ? 0 : 1;\r
2009 TrsTrb = (TRB_TEMPLATE *)TrsRing->RingSeg0; // Use host address\r
2010 }\r
2011 }\r
2012\r
2013 ASSERT (Index != TrsRing->TrbNumber);\r
2014\r
2015 if (TrsTrb != TrsRing->RingEnqueue) {\r
2016 TrsRing->RingEnqueue = TrsTrb;\r
2017 }\r
2018\r
2019 //\r
2020 // Clear the Trb context for enqueue, but reserve the PCS bit\r
2021 //\r
2022 TrsTrb->Parameter1 = 0;\r
2023 TrsTrb->Parameter2 = 0;\r
2024 TrsTrb->Status = 0;\r
2025 TrsTrb->RsvdZ1 = 0;\r
2026 TrsTrb->Type = 0;\r
2027 TrsTrb->Control = 0;\r
2028\r
2029 return EFI_SUCCESS;\r
2030}\r
2031\r
2032/**\r
2033 Check if there is a new generated event.\r
2034\r
2035 @param Xhc The XHCI Instance.\r
2036 @param EvtRing The event ring to check.\r
2037 @param NewEvtTrb The new event TRB found.\r
2038\r
2039 @retval EFI_SUCCESS Found a new event TRB at the event ring.\r
2040 @retval EFI_NOT_READY The event ring has no new event.\r
2041\r
2042**/\r
2043EFI_STATUS\r
2044EFIAPI\r
2045XhcCheckNewEvent (\r
2046 IN USB_XHCI_INSTANCE *Xhc,\r
2047 IN EVENT_RING *EvtRing,\r
2048 OUT TRB_TEMPLATE **NewEvtTrb\r
2049 )\r
2050{\r
2051 ASSERT (EvtRing != NULL);\r
2052\r
2053 *NewEvtTrb = EvtRing->EventRingDequeue;\r
2054\r
2055 if (EvtRing->EventRingDequeue == EvtRing->EventRingEnqueue) {\r
2056 return EFI_NOT_READY;\r
2057 }\r
2058\r
2059 EvtRing->EventRingDequeue++;\r
2060 //\r
2061 // If the dequeue pointer is beyond the ring, then roll-back it to the begining of the ring.\r
2062 //\r
2063 if ((UINTN)EvtRing->EventRingDequeue >= ((UINTN)EvtRing->EventRingSeg0 + sizeof (TRB_TEMPLATE) * EvtRing->TrbNumber)) {\r
2064 EvtRing->EventRingDequeue = EvtRing->EventRingSeg0;\r
2065 }\r
2066\r
2067 return EFI_SUCCESS;\r
2068}\r
2069\r
2070/**\r
2071 Ring the door bell to notify XHCI there is a transaction to be executed.\r
2072\r
2073 @param Xhc The XHCI Instance.\r
2074 @param SlotId The slot id of the target device.\r
2075 @param Dci The device context index of the target slot or endpoint.\r
2076\r
2077 @retval EFI_SUCCESS Successfully ring the door bell.\r
2078\r
2079**/\r
2080EFI_STATUS\r
2081EFIAPI\r
2082XhcRingDoorBell (\r
2083 IN USB_XHCI_INSTANCE *Xhc,\r
2084 IN UINT8 SlotId,\r
2085 IN UINT8 Dci\r
2086 )\r
2087{\r
2088 if (SlotId == 0) {\r
2089 XhcWriteDoorBellReg (Xhc, 0, 0);\r
2090 } else {\r
2091 XhcWriteDoorBellReg (Xhc, SlotId * sizeof (UINT32), Dci);\r
2092 }\r
2093\r
2094 return EFI_SUCCESS;\r
2095}\r
2096\r
2097/**\r
2098 Ring the door bell to notify XHCI there is a transaction to be executed through URB.\r
2099\r
2100 @param Xhc The XHCI Instance.\r
2101 @param Urb The URB to be rung.\r
2102\r
2103 @retval EFI_SUCCESS Successfully ring the door bell.\r
2104\r
2105**/\r
2106EFI_STATUS\r
2107RingIntTransferDoorBell (\r
2108 IN USB_XHCI_INSTANCE *Xhc,\r
2109 IN URB *Urb\r
2110 )\r
2111{\r
2112 UINT8 SlotId;\r
2113 UINT8 Dci;\r
2114\r
2115 SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
2116 Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
2117 XhcRingDoorBell (Xhc, SlotId, Dci);\r
2118 return EFI_SUCCESS;\r
2119}\r
2120\r
2121/**\r
2122 Assign and initialize the device slot for a new device.\r
2123\r
2124 @param Xhc The XHCI Instance.\r
2125 @param ParentRouteChart The route string pointed to the parent device.\r
2126 @param ParentPort The port at which the device is located.\r
2127 @param RouteChart The route string pointed to the device.\r
2128 @param DeviceSpeed The device speed.\r
2129\r
2130 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
2131\r
2132**/\r
2133EFI_STATUS\r
2134EFIAPI\r
2135XhcInitializeDeviceSlot (\r
2136 IN USB_XHCI_INSTANCE *Xhc,\r
2137 IN USB_DEV_ROUTE ParentRouteChart,\r
2138 IN UINT16 ParentPort,\r
2139 IN USB_DEV_ROUTE RouteChart,\r
2140 IN UINT8 DeviceSpeed\r
2141 )\r
2142{\r
2143 EFI_STATUS Status;\r
2144 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2145 INPUT_CONTEXT *InputContext;\r
2146 DEVICE_CONTEXT *OutputContext;\r
2147 TRANSFER_RING *EndpointTransferRing;\r
2148 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2149 UINT8 DeviceAddress;\r
2150 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2151 UINT8 SlotId;\r
2152 UINT8 ParentSlotId;\r
2153 DEVICE_CONTEXT *ParentDeviceContext;\r
2154 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2155\r
2156 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
2157 CmdTrb.CycleBit = 1;\r
2158 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
2159\r
2160 Status = XhcCmdTransfer (\r
2161 Xhc,\r
2162 (TRB_TEMPLATE *)(UINTN)&CmdTrb,\r
2163 XHC_GENERIC_TIMEOUT,\r
2164 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2165 );\r
2166 if (EFI_ERROR (Status)) {\r
2167 DEBUG ((DEBUG_ERROR, "XhcInitializeDeviceSlot: Enable Slot Failed, Status = %r\n", Status));\r
2168 return Status;\r
2169 }\r
2170\r
2171 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
2172 DEBUG ((DEBUG_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
2173 SlotId = (UINT8)EvtTrb->SlotId;\r
2174 ASSERT (SlotId != 0);\r
2175\r
2176 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2177 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2178 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2179 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2180 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
2181\r
2182 //\r
2183 // 4.3.3 Device Slot Initialization\r
2184 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
2185 //\r
2186 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT), FALSE);\r
2187 ASSERT (InputContext != NULL);\r
2188 ASSERT (((UINTN)InputContext & 0x3F) == 0);\r
2189 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
2190\r
2191 Xhc->UsbDevContext[SlotId].InputContext = (VOID *)InputContext;\r
2192\r
2193 //\r
2194 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2195 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2196 // Context are affected by the command.\r
2197 //\r
2198 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
2199\r
2200 //\r
2201 // 3) Initialize the Input Slot Context data structure\r
2202 //\r
2203 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
2204 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2205 InputContext->Slot.ContextEntries = 1;\r
2206 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
2207\r
2208 if (RouteChart.Route.RouteString) {\r
2209 //\r
2210 // The device is behind of hub device.\r
2211 //\r
2212 ParentSlotId = XhcRouteStringToSlotId (Xhc, ParentRouteChart);\r
2213 ASSERT (ParentSlotId != 0);\r
2214 //\r
2215 // if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2216 //\r
2217 ParentDeviceContext = (DEVICE_CONTEXT *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
2218 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2219 (ParentDeviceContext->Slot.TTHubSlotId == 0))\r
2220 {\r
2221 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2222 //\r
2223 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2224 // environment from Full/Low speed signaling environment for a device\r
2225 //\r
2226 InputContext->Slot.TTPortNum = ParentPort;\r
2227 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2228 }\r
2229 } else {\r
2230 //\r
2231 // Inherit the TT parameters from parent device.\r
2232 //\r
2233 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2234 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2235 //\r
2236 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2237 //\r
2238 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2239 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2240 }\r
2241 }\r
2242 }\r
2243\r
2244 //\r
2245 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
2246 //\r
2247 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2248 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2249 CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
2250 //\r
2251 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2252 //\r
2253 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2254\r
2255 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2256 InputContext->EP[0].MaxPacketSize = 512;\r
2257 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2258 InputContext->EP[0].MaxPacketSize = 64;\r
2259 } else {\r
2260 InputContext->EP[0].MaxPacketSize = 8;\r
2261 }\r
2262\r
2263 //\r
2264 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2265 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2266 //\r
2267 InputContext->EP[0].AverageTRBLength = 8;\r
2268 InputContext->EP[0].MaxBurstSize = 0;\r
2269 InputContext->EP[0].Interval = 0;\r
2270 InputContext->EP[0].MaxPStreams = 0;\r
2271 InputContext->EP[0].Mult = 0;\r
2272 InputContext->EP[0].CErr = 3;\r
2273\r
2274 //\r
2275 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2276 //\r
2277 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2278 Xhc->MemPool,\r
2279 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2280 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2281 );\r
2282 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2283 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2284\r
2285 //\r
2286 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2287 //\r
2288 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT), FALSE);\r
2289 ASSERT (OutputContext != NULL);\r
2290 ASSERT (((UINTN)OutputContext & 0x3F) == 0);\r
2291 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));\r
2292\r
2293 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
2294 //\r
2295 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2296 // a pointer to the Output Device Context data structure (6.2.1).\r
2297 //\r
2298 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT));\r
2299 //\r
2300 // Fill DCBAA with PCI device address\r
2301 //\r
2302 Xhc->DCBAA[SlotId] = (UINT64)(UINTN)PhyAddr;\r
2303\r
2304 //\r
2305 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2306 // Context data structure described above.\r
2307 //\r
2308 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2309 // to device.\r
2310 //\r
2311 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
2312 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
2313 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
2314 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2315 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2316 CmdTrbAddr.CycleBit = 1;\r
2317 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
2318 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2319 Status = XhcCmdTransfer (\r
2320 Xhc,\r
2321 (TRB_TEMPLATE *)(UINTN)&CmdTrbAddr,\r
2322 XHC_GENERIC_TIMEOUT,\r
2323 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2324 );\r
2325 if (!EFI_ERROR (Status)) {\r
2326 DeviceAddress = (UINT8)((DEVICE_CONTEXT *)OutputContext)->Slot.DeviceAddress;\r
2327 DEBUG ((DEBUG_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2328 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2329 } else {\r
2330 DEBUG ((DEBUG_ERROR, " Slot %d address not assigned successfully. Status = %r\n", SlotId, Status));\r
2331 XhcDisableSlotCmd (Xhc, SlotId);\r
2332 }\r
2333\r
2334 return Status;\r
2335}\r
2336\r
2337/**\r
2338 Assign and initialize the device slot for a new device.\r
2339\r
2340 @param Xhc The XHCI Instance.\r
2341 @param ParentRouteChart The route string pointed to the parent device.\r
2342 @param ParentPort The port at which the device is located.\r
2343 @param RouteChart The route string pointed to the device.\r
2344 @param DeviceSpeed The device speed.\r
2345\r
2346 @retval EFI_SUCCESS Successfully assign a slot to the device and assign an address to it.\r
2347\r
2348**/\r
2349EFI_STATUS\r
2350EFIAPI\r
2351XhcInitializeDeviceSlot64 (\r
2352 IN USB_XHCI_INSTANCE *Xhc,\r
2353 IN USB_DEV_ROUTE ParentRouteChart,\r
2354 IN UINT16 ParentPort,\r
2355 IN USB_DEV_ROUTE RouteChart,\r
2356 IN UINT8 DeviceSpeed\r
2357 )\r
2358{\r
2359 EFI_STATUS Status;\r
2360 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
2361 INPUT_CONTEXT_64 *InputContext;\r
2362 DEVICE_CONTEXT_64 *OutputContext;\r
2363 TRANSFER_RING *EndpointTransferRing;\r
2364 CMD_TRB_ADDRESS_DEVICE CmdTrbAddr;\r
2365 UINT8 DeviceAddress;\r
2366 CMD_TRB_ENABLE_SLOT CmdTrb;\r
2367 UINT8 SlotId;\r
2368 UINT8 ParentSlotId;\r
2369 DEVICE_CONTEXT_64 *ParentDeviceContext;\r
2370 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2371\r
2372 ZeroMem (&CmdTrb, sizeof (CMD_TRB_ENABLE_SLOT));\r
2373 CmdTrb.CycleBit = 1;\r
2374 CmdTrb.Type = TRB_TYPE_EN_SLOT;\r
2375\r
2376 Status = XhcCmdTransfer (\r
2377 Xhc,\r
2378 (TRB_TEMPLATE *)(UINTN)&CmdTrb,\r
2379 XHC_GENERIC_TIMEOUT,\r
2380 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2381 );\r
2382 if (EFI_ERROR (Status)) {\r
2383 DEBUG ((DEBUG_ERROR, "XhcInitializeDeviceSlot64: Enable Slot Failed, Status = %r\n", Status));\r
2384 return Status;\r
2385 }\r
2386\r
2387 ASSERT (EvtTrb->SlotId <= Xhc->MaxSlotsEn);\r
2388 DEBUG ((DEBUG_INFO, "Enable Slot Successfully, The Slot ID = 0x%x\n", EvtTrb->SlotId));\r
2389 SlotId = (UINT8)EvtTrb->SlotId;\r
2390 ASSERT (SlotId != 0);\r
2391\r
2392 ZeroMem (&Xhc->UsbDevContext[SlotId], sizeof (USB_DEV_CONTEXT));\r
2393 Xhc->UsbDevContext[SlotId].Enabled = TRUE;\r
2394 Xhc->UsbDevContext[SlotId].SlotId = SlotId;\r
2395 Xhc->UsbDevContext[SlotId].RouteString.Dword = RouteChart.Dword;\r
2396 Xhc->UsbDevContext[SlotId].ParentRouteString.Dword = ParentRouteChart.Dword;\r
2397\r
2398 //\r
2399 // 4.3.3 Device Slot Initialization\r
2400 // 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.\r
2401 //\r
2402 InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64), FALSE);\r
2403 ASSERT (InputContext != NULL);\r
2404 ASSERT (((UINTN)InputContext & 0x3F) == 0);\r
2405 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
2406\r
2407 Xhc->UsbDevContext[SlotId].InputContext = (VOID *)InputContext;\r
2408\r
2409 //\r
2410 // 2) Initialize the Input Control Context (6.2.5.1) of the Input Context by setting the A0 and A1\r
2411 // flags to '1'. These flags indicate that the Slot Context and the Endpoint 0 Context of the Input\r
2412 // Context are affected by the command.\r
2413 //\r
2414 InputContext->InputControlContext.Dword2 |= (BIT0 | BIT1);\r
2415\r
2416 //\r
2417 // 3) Initialize the Input Slot Context data structure\r
2418 //\r
2419 InputContext->Slot.RouteString = RouteChart.Route.RouteString;\r
2420 InputContext->Slot.Speed = DeviceSpeed + 1;\r
2421 InputContext->Slot.ContextEntries = 1;\r
2422 InputContext->Slot.RootHubPortNum = RouteChart.Route.RootPortNum;\r
2423\r
2424 if (RouteChart.Route.RouteString) {\r
2425 //\r
2426 // The device is behind of hub device.\r
2427 //\r
2428 ParentSlotId = XhcRouteStringToSlotId (Xhc, ParentRouteChart);\r
2429 ASSERT (ParentSlotId != 0);\r
2430 //\r
2431 // if the Full/Low device attached to a High Speed Hub, Init the TTPortNum and TTHubSlotId field of slot context\r
2432 //\r
2433 ParentDeviceContext = (DEVICE_CONTEXT_64 *)Xhc->UsbDevContext[ParentSlotId].OutputContext;\r
2434 if ((ParentDeviceContext->Slot.TTPortNum == 0) &&\r
2435 (ParentDeviceContext->Slot.TTHubSlotId == 0))\r
2436 {\r
2437 if ((ParentDeviceContext->Slot.Speed == (EFI_USB_SPEED_HIGH + 1)) && (DeviceSpeed < EFI_USB_SPEED_HIGH)) {\r
2438 //\r
2439 // Full/Low device attached to High speed hub port that isolates the high speed signaling\r
2440 // environment from Full/Low speed signaling environment for a device\r
2441 //\r
2442 InputContext->Slot.TTPortNum = ParentPort;\r
2443 InputContext->Slot.TTHubSlotId = ParentSlotId;\r
2444 }\r
2445 } else {\r
2446 //\r
2447 // Inherit the TT parameters from parent device.\r
2448 //\r
2449 InputContext->Slot.TTPortNum = ParentDeviceContext->Slot.TTPortNum;\r
2450 InputContext->Slot.TTHubSlotId = ParentDeviceContext->Slot.TTHubSlotId;\r
2451 //\r
2452 // If the device is a High speed device then down the speed to be the same as its parent Hub\r
2453 //\r
2454 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2455 InputContext->Slot.Speed = ParentDeviceContext->Slot.Speed;\r
2456 }\r
2457 }\r
2458 }\r
2459\r
2460 //\r
2461 // 4) Allocate and initialize the Transfer Ring for the Default Control Endpoint.\r
2462 //\r
2463 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2464 Xhc->UsbDevContext[SlotId].EndpointTransferRing[0] = EndpointTransferRing;\r
2465 CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0]);\r
2466 //\r
2467 // 5) Initialize the Input default control Endpoint 0 Context (6.2.3).\r
2468 //\r
2469 InputContext->EP[0].EPType = ED_CONTROL_BIDIR;\r
2470\r
2471 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2472 InputContext->EP[0].MaxPacketSize = 512;\r
2473 } else if (DeviceSpeed == EFI_USB_SPEED_HIGH) {\r
2474 InputContext->EP[0].MaxPacketSize = 64;\r
2475 } else {\r
2476 InputContext->EP[0].MaxPacketSize = 8;\r
2477 }\r
2478\r
2479 //\r
2480 // Initial value of Average TRB Length for Control endpoints would be 8B, Interrupt endpoints\r
2481 // 1KB, and Bulk and Isoch endpoints 3KB.\r
2482 //\r
2483 InputContext->EP[0].AverageTRBLength = 8;\r
2484 InputContext->EP[0].MaxBurstSize = 0;\r
2485 InputContext->EP[0].Interval = 0;\r
2486 InputContext->EP[0].MaxPStreams = 0;\r
2487 InputContext->EP[0].Mult = 0;\r
2488 InputContext->EP[0].CErr = 3;\r
2489\r
2490 //\r
2491 // Init the DCS(dequeue cycle state) as the transfer ring's CCS\r
2492 //\r
2493 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2494 Xhc->MemPool,\r
2495 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[0])->RingSeg0,\r
2496 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2497 );\r
2498 InputContext->EP[0].PtrLo = XHC_LOW_32BIT (PhyAddr) | BIT0;\r
2499 InputContext->EP[0].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2500\r
2501 //\r
2502 // 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.\r
2503 //\r
2504 OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64), FALSE);\r
2505 ASSERT (OutputContext != NULL);\r
2506 ASSERT (((UINTN)OutputContext & 0x3F) == 0);\r
2507 ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2508\r
2509 Xhc->UsbDevContext[SlotId].OutputContext = OutputContext;\r
2510 //\r
2511 // 7) Load the appropriate (Device Slot ID) entry in the Device Context Base Address Array (5.4.6) with\r
2512 // a pointer to the Output Device Context data structure (6.2.1).\r
2513 //\r
2514 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2515 //\r
2516 // Fill DCBAA with PCI device address\r
2517 //\r
2518 Xhc->DCBAA[SlotId] = (UINT64)(UINTN)PhyAddr;\r
2519\r
2520 //\r
2521 // 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
2522 // Context data structure described above.\r
2523 //\r
2524 // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
2525 // to device.\r
2526 //\r
2527 gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
2528 ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
2529 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
2530 CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2531 CmdTrbAddr.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2532 CmdTrbAddr.CycleBit = 1;\r
2533 CmdTrbAddr.Type = TRB_TYPE_ADDRESS_DEV;\r
2534 CmdTrbAddr.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
2535 Status = XhcCmdTransfer (\r
2536 Xhc,\r
2537 (TRB_TEMPLATE *)(UINTN)&CmdTrbAddr,\r
2538 XHC_GENERIC_TIMEOUT,\r
2539 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2540 );\r
2541 if (!EFI_ERROR (Status)) {\r
2542 DeviceAddress = (UINT8)((DEVICE_CONTEXT_64 *)OutputContext)->Slot.DeviceAddress;\r
2543 DEBUG ((DEBUG_INFO, " Address %d assigned successfully\n", DeviceAddress));\r
2544 Xhc->UsbDevContext[SlotId].XhciDevAddr = DeviceAddress;\r
2545 } else {\r
2546 DEBUG ((DEBUG_ERROR, " Slot %d address not assigned successfully. Status = %r\n", SlotId, Status));\r
2547 XhcDisableSlotCmd64 (Xhc, SlotId);\r
2548 }\r
2549\r
2550 return Status;\r
2551}\r
2552\r
2553/**\r
2554 Disable the specified device slot.\r
2555\r
2556 @param Xhc The XHCI Instance.\r
2557 @param SlotId The slot id to be disabled.\r
2558\r
2559 @retval EFI_SUCCESS Successfully disable the device slot.\r
2560\r
2561**/\r
2562EFI_STATUS\r
2563EFIAPI\r
2564XhcDisableSlotCmd (\r
2565 IN USB_XHCI_INSTANCE *Xhc,\r
2566 IN UINT8 SlotId\r
2567 )\r
2568{\r
2569 EFI_STATUS Status;\r
2570 TRB_TEMPLATE *EvtTrb;\r
2571 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2572 UINT8 Index;\r
2573 VOID *RingSeg;\r
2574\r
2575 //\r
2576 // Disable the device slots occupied by these devices on its downstream ports.\r
2577 // Entry 0 is reserved.\r
2578 //\r
2579 for (Index = 0; Index < 255; Index++) {\r
2580 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2581 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2582 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword))\r
2583 {\r
2584 continue;\r
2585 }\r
2586\r
2587 Status = XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2588\r
2589 if (EFI_ERROR (Status)) {\r
2590 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2591 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2592 }\r
2593 }\r
2594\r
2595 //\r
2596 // Construct the disable slot command\r
2597 //\r
2598 DEBUG ((DEBUG_INFO, "Disable device slot %d!\n", SlotId));\r
2599\r
2600 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2601 CmdTrbDisSlot.CycleBit = 1;\r
2602 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2603 CmdTrbDisSlot.SlotId = SlotId;\r
2604 Status = XhcCmdTransfer (\r
2605 Xhc,\r
2606 (TRB_TEMPLATE *)(UINTN)&CmdTrbDisSlot,\r
2607 XHC_GENERIC_TIMEOUT,\r
2608 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2609 );\r
2610 if (EFI_ERROR (Status)) {\r
2611 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2612 return Status;\r
2613 }\r
2614\r
2615 //\r
2616 // Free the slot's device context entry\r
2617 //\r
2618 Xhc->DCBAA[SlotId] = 0;\r
2619\r
2620 //\r
2621 // Free the slot related data structure\r
2622 //\r
2623 for (Index = 0; Index < 31; Index++) {\r
2624 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2625 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2626 if (RingSeg != NULL) {\r
2627 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
2628 }\r
2629\r
2630 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
2631 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
2632 }\r
2633 }\r
2634\r
2635 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2636 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2637 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2638 }\r
2639 }\r
2640\r
2641 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2642 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2643 }\r
2644\r
2645 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
2646 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
2647 }\r
2648\r
2649 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
2650 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT));\r
2651 }\r
2652\r
2653 //\r
2654 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2655 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2656 // remove urb from XHCI's asynchronous transfer list.\r
2657 //\r
2658 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2659 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2660\r
2661 return Status;\r
2662}\r
2663\r
2664/**\r
2665 Disable the specified device slot.\r
2666\r
2667 @param Xhc The XHCI Instance.\r
2668 @param SlotId The slot id to be disabled.\r
2669\r
2670 @retval EFI_SUCCESS Successfully disable the device slot.\r
2671\r
2672**/\r
2673EFI_STATUS\r
2674EFIAPI\r
2675XhcDisableSlotCmd64 (\r
2676 IN USB_XHCI_INSTANCE *Xhc,\r
2677 IN UINT8 SlotId\r
2678 )\r
2679{\r
2680 EFI_STATUS Status;\r
2681 TRB_TEMPLATE *EvtTrb;\r
2682 CMD_TRB_DISABLE_SLOT CmdTrbDisSlot;\r
2683 UINT8 Index;\r
2684 VOID *RingSeg;\r
2685\r
2686 //\r
2687 // Disable the device slots occupied by these devices on its downstream ports.\r
2688 // Entry 0 is reserved.\r
2689 //\r
2690 for (Index = 0; Index < 255; Index++) {\r
2691 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2692 (Xhc->UsbDevContext[Index + 1].SlotId == 0) ||\r
2693 (Xhc->UsbDevContext[Index + 1].ParentRouteString.Dword != Xhc->UsbDevContext[SlotId].RouteString.Dword))\r
2694 {\r
2695 continue;\r
2696 }\r
2697\r
2698 Status = XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2699\r
2700 if (EFI_ERROR (Status)) {\r
2701 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: failed to disable child, ignore error\n"));\r
2702 Xhc->UsbDevContext[Index + 1].SlotId = 0;\r
2703 }\r
2704 }\r
2705\r
2706 //\r
2707 // Construct the disable slot command\r
2708 //\r
2709 DEBUG ((DEBUG_INFO, "Disable device slot %d!\n", SlotId));\r
2710\r
2711 ZeroMem (&CmdTrbDisSlot, sizeof (CmdTrbDisSlot));\r
2712 CmdTrbDisSlot.CycleBit = 1;\r
2713 CmdTrbDisSlot.Type = TRB_TYPE_DIS_SLOT;\r
2714 CmdTrbDisSlot.SlotId = SlotId;\r
2715 Status = XhcCmdTransfer (\r
2716 Xhc,\r
2717 (TRB_TEMPLATE *)(UINTN)&CmdTrbDisSlot,\r
2718 XHC_GENERIC_TIMEOUT,\r
2719 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
2720 );\r
2721 if (EFI_ERROR (Status)) {\r
2722 DEBUG ((DEBUG_ERROR, "XhcDisableSlotCmd: Disable Slot Command Failed, Status = %r\n", Status));\r
2723 return Status;\r
2724 }\r
2725\r
2726 //\r
2727 // Free the slot's device context entry\r
2728 //\r
2729 Xhc->DCBAA[SlotId] = 0;\r
2730\r
2731 //\r
2732 // Free the slot related data structure\r
2733 //\r
2734 for (Index = 0; Index < 31; Index++) {\r
2735 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] != NULL) {\r
2736 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index])->RingSeg0;\r
2737 if (RingSeg != NULL) {\r
2738 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
2739 }\r
2740\r
2741 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index]);\r
2742 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Index] = NULL;\r
2743 }\r
2744 }\r
2745\r
2746 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
2747 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] != NULL) {\r
2748 FreePool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
2749 }\r
2750 }\r
2751\r
2752 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting != NULL) {\r
2753 FreePool (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting);\r
2754 }\r
2755\r
2756 if (Xhc->UsbDevContext[SlotId].InputContext != NULL) {\r
2757 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
2758 }\r
2759\r
2760 if (Xhc->UsbDevContext[SlotId].OutputContext != NULL) {\r
2761 UsbHcFreeMem (Xhc->MemPool, Xhc->UsbDevContext[SlotId].OutputContext, sizeof (DEVICE_CONTEXT_64));\r
2762 }\r
2763\r
2764 //\r
2765 // Doesn't zero the entry because XhcAsyncInterruptTransfer() may be invoked to remove the established\r
2766 // asynchronous interrupt pipe after the device is disabled. It needs the device address mapping info to\r
2767 // remove urb from XHCI's asynchronous transfer list.\r
2768 //\r
2769 Xhc->UsbDevContext[SlotId].Enabled = FALSE;\r
2770 Xhc->UsbDevContext[SlotId].SlotId = 0;\r
2771\r
2772 return Status;\r
2773}\r
2774\r
2775/**\r
2776 Initialize endpoint context in input context.\r
2777\r
2778 @param Xhc The XHCI Instance.\r
2779 @param SlotId The slot id to be configured.\r
2780 @param DeviceSpeed The device's speed.\r
2781 @param InputContext The pointer to the input context.\r
2782 @param IfDesc The pointer to the usb device interface descriptor.\r
2783\r
2784 @return The maximum device context index of endpoint.\r
2785\r
2786**/\r
2787UINT8\r
2788EFIAPI\r
2789XhcInitializeEndpointContext (\r
2790 IN USB_XHCI_INSTANCE *Xhc,\r
2791 IN UINT8 SlotId,\r
2792 IN UINT8 DeviceSpeed,\r
2793 IN INPUT_CONTEXT *InputContext,\r
2794 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2795 )\r
2796{\r
2797 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
2798 UINTN NumEp;\r
2799 UINTN EpIndex;\r
2800 UINT8 EpAddr;\r
2801 UINT8 Direction;\r
2802 UINT8 Dci;\r
2803 UINT8 MaxDci;\r
2804 EFI_PHYSICAL_ADDRESS PhyAddr;\r
2805 UINT8 Interval;\r
2806 TRANSFER_RING *EndpointTransferRing;\r
2807\r
2808 MaxDci = 0;\r
2809\r
2810 NumEp = IfDesc->NumEndpoints;\r
2811 if (NumEp == 0) {\r
2812 MaxDci = 1;\r
2813 }\r
2814\r
2815 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
2816 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
2817 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
2818 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2819 }\r
2820\r
2821 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
2822 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2823 continue;\r
2824 }\r
2825\r
2826 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
2827 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
2828\r
2829 Dci = XhcEndpointToDci (EpAddr, Direction);\r
2830 ASSERT (Dci < 32);\r
2831 if (Dci > MaxDci) {\r
2832 MaxDci = Dci;\r
2833 }\r
2834\r
2835 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
2836 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
2837\r
2838 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
2839 //\r
2840 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
2841 //\r
2842 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2843 } else {\r
2844 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2845 }\r
2846\r
2847 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
2848 case USB_ENDPOINT_BULK:\r
2849 if (Direction == EfiUsbDataIn) {\r
2850 InputContext->EP[Dci-1].CErr = 3;\r
2851 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
2852 } else {\r
2853 InputContext->EP[Dci-1].CErr = 3;\r
2854 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
2855 }\r
2856\r
2857 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2858 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2859 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2860 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
2861 CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2862 DEBUG ((\r
2863 DEBUG_INFO,\r
2864 "Endpoint[%x]: Created BULK ring [%p~%p)\n",\r
2865 EpDesc->EndpointAddress,\r
2866 EndpointTransferRing->RingSeg0,\r
2867 (UINTN)EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2868 ));\r
2869 }\r
2870\r
2871 break;\r
2872 case USB_ENDPOINT_ISO:\r
2873 if (Direction == EfiUsbDataIn) {\r
2874 InputContext->EP[Dci-1].CErr = 0;\r
2875 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
2876 } else {\r
2877 InputContext->EP[Dci-1].CErr = 0;\r
2878 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
2879 }\r
2880\r
2881 //\r
2882 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
2883 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
2884 //\r
2885 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
2886 Interval = EpDesc->Interval;\r
2887 ASSERT (Interval >= 1 && Interval <= 16);\r
2888 InputContext->EP[Dci-1].Interval = Interval + 2;\r
2889 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2890 Interval = EpDesc->Interval;\r
2891 ASSERT (Interval >= 1 && Interval <= 16);\r
2892 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2893 }\r
2894\r
2895 //\r
2896 // Do not support isochronous transfer now.\r
2897 //\r
2898 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
2899 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2900 continue;\r
2901 case USB_ENDPOINT_INTERRUPT:\r
2902 if (Direction == EfiUsbDataIn) {\r
2903 InputContext->EP[Dci-1].CErr = 3;\r
2904 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
2905 } else {\r
2906 InputContext->EP[Dci-1].CErr = 3;\r
2907 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
2908 }\r
2909\r
2910 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2911 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
2912 //\r
2913 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
2914 //\r
2915 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
2916 Interval = EpDesc->Interval;\r
2917 //\r
2918 // Calculate through the bInterval field of Endpoint descriptor.\r
2919 //\r
2920 ASSERT (Interval != 0);\r
2921 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32 ((UINT32)Interval) + 3;\r
2922 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
2923 Interval = EpDesc->Interval;\r
2924 ASSERT (Interval >= 1 && Interval <= 16);\r
2925 //\r
2926 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
2927 //\r
2928 InputContext->EP[Dci-1].Interval = Interval - 1;\r
2929 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
2930 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
2931 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
2932 InputContext->EP[Dci-1].CErr = 3;\r
2933 }\r
2934\r
2935 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
2936 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
2937 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
2938 CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
2939 DEBUG ((\r
2940 DEBUG_INFO,\r
2941 "Endpoint[%x]: Created INT ring [%p~%p)\n",\r
2942 EpDesc->EndpointAddress,\r
2943 EndpointTransferRing->RingSeg0,\r
2944 (UINTN)EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
2945 ));\r
2946 }\r
2947\r
2948 break;\r
2949\r
2950 case USB_ENDPOINT_CONTROL:\r
2951 //\r
2952 // Do not support control transfer now.\r
2953 //\r
2954 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
2955 default:\r
2956 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));\r
2957 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2958 continue;\r
2959 }\r
2960\r
2961 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
2962 Xhc->MemPool,\r
2963 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
2964 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
2965 );\r
2966 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
2967 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
2968 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
2969 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
2970\r
2971 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
2972 }\r
2973\r
2974 return MaxDci;\r
2975}\r
2976\r
2977/**\r
2978 Initialize endpoint context in input context.\r
2979\r
2980 @param Xhc The XHCI Instance.\r
2981 @param SlotId The slot id to be configured.\r
2982 @param DeviceSpeed The device's speed.\r
2983 @param InputContext The pointer to the input context.\r
2984 @param IfDesc The pointer to the usb device interface descriptor.\r
2985\r
2986 @return The maximum device context index of endpoint.\r
2987\r
2988**/\r
2989UINT8\r
2990EFIAPI\r
2991XhcInitializeEndpointContext64 (\r
2992 IN USB_XHCI_INSTANCE *Xhc,\r
2993 IN UINT8 SlotId,\r
2994 IN UINT8 DeviceSpeed,\r
2995 IN INPUT_CONTEXT_64 *InputContext,\r
2996 IN USB_INTERFACE_DESCRIPTOR *IfDesc\r
2997 )\r
2998{\r
2999 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3000 UINTN NumEp;\r
3001 UINTN EpIndex;\r
3002 UINT8 EpAddr;\r
3003 UINT8 Direction;\r
3004 UINT8 Dci;\r
3005 UINT8 MaxDci;\r
3006 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3007 UINT8 Interval;\r
3008 TRANSFER_RING *EndpointTransferRing;\r
3009\r
3010 MaxDci = 0;\r
3011\r
3012 NumEp = IfDesc->NumEndpoints;\r
3013 if (NumEp == 0) {\r
3014 MaxDci = 1;\r
3015 }\r
3016\r
3017 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDesc + 1);\r
3018 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3019 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3020 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3021 }\r
3022\r
3023 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3024 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3025 continue;\r
3026 }\r
3027\r
3028 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
3029 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3030\r
3031 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3032 ASSERT (Dci < 32);\r
3033 if (Dci > MaxDci) {\r
3034 MaxDci = Dci;\r
3035 }\r
3036\r
3037 InputContext->InputControlContext.Dword2 |= (BIT0 << Dci);\r
3038 InputContext->EP[Dci-1].MaxPacketSize = EpDesc->MaxPacketSize;\r
3039\r
3040 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
3041 //\r
3042 // 6.2.3.4, shall be set to the value defined in the bMaxBurst field of the SuperSpeed Endpoint Companion Descriptor.\r
3043 //\r
3044 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
3045 } else {\r
3046 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
3047 }\r
3048\r
3049 switch (EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK) {\r
3050 case USB_ENDPOINT_BULK:\r
3051 if (Direction == EfiUsbDataIn) {\r
3052 InputContext->EP[Dci-1].CErr = 3;\r
3053 InputContext->EP[Dci-1].EPType = ED_BULK_IN;\r
3054 } else {\r
3055 InputContext->EP[Dci-1].CErr = 3;\r
3056 InputContext->EP[Dci-1].EPType = ED_BULK_OUT;\r
3057 }\r
3058\r
3059 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
3060 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
3061 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
3062 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
3063 CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
3064 DEBUG ((\r
3065 DEBUG_INFO,\r
3066 "Endpoint64[%x]: Created BULK ring [%p~%p)\n",\r
3067 EpDesc->EndpointAddress,\r
3068 EndpointTransferRing->RingSeg0,\r
3069 (UINTN)EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
3070 ));\r
3071 }\r
3072\r
3073 break;\r
3074 case USB_ENDPOINT_ISO:\r
3075 if (Direction == EfiUsbDataIn) {\r
3076 InputContext->EP[Dci-1].CErr = 0;\r
3077 InputContext->EP[Dci-1].EPType = ED_ISOCH_IN;\r
3078 } else {\r
3079 InputContext->EP[Dci-1].CErr = 0;\r
3080 InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
3081 }\r
3082\r
3083 //\r
3084 // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
3085 // Refer to XHCI 1.1 spec section 6.2.3.6.\r
3086 //\r
3087 if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
3088 Interval = EpDesc->Interval;\r
3089 ASSERT (Interval >= 1 && Interval <= 16);\r
3090 InputContext->EP[Dci-1].Interval = Interval + 2;\r
3091 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
3092 Interval = EpDesc->Interval;\r
3093 ASSERT (Interval >= 1 && Interval <= 16);\r
3094 InputContext->EP[Dci-1].Interval = Interval - 1;\r
3095 }\r
3096\r
3097 //\r
3098 // Do not support isochronous transfer now.\r
3099 //\r
3100 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
3101 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3102 continue;\r
3103 case USB_ENDPOINT_INTERRUPT:\r
3104 if (Direction == EfiUsbDataIn) {\r
3105 InputContext->EP[Dci-1].CErr = 3;\r
3106 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_IN;\r
3107 } else {\r
3108 InputContext->EP[Dci-1].CErr = 3;\r
3109 InputContext->EP[Dci-1].EPType = ED_INTERRUPT_OUT;\r
3110 }\r
3111\r
3112 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
3113 InputContext->EP[Dci-1].MaxESITPayload = EpDesc->MaxPacketSize;\r
3114 //\r
3115 // Get the bInterval from descriptor and init the the interval field of endpoint context\r
3116 //\r
3117 if ((DeviceSpeed == EFI_USB_SPEED_FULL) || (DeviceSpeed == EFI_USB_SPEED_LOW)) {\r
3118 Interval = EpDesc->Interval;\r
3119 //\r
3120 // Calculate through the bInterval field of Endpoint descriptor.\r
3121 //\r
3122 ASSERT (Interval != 0);\r
3123 InputContext->EP[Dci-1].Interval = (UINT32)HighBitSet32 ((UINT32)Interval) + 3;\r
3124 } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
3125 Interval = EpDesc->Interval;\r
3126 ASSERT (Interval >= 1 && Interval <= 16);\r
3127 //\r
3128 // Refer to XHCI 1.0 spec section 6.2.3.6, table 61\r
3129 //\r
3130 InputContext->EP[Dci-1].Interval = Interval - 1;\r
3131 InputContext->EP[Dci-1].AverageTRBLength = 0x1000;\r
3132 InputContext->EP[Dci-1].MaxESITPayload = 0x0002;\r
3133 InputContext->EP[Dci-1].MaxBurstSize = 0x0;\r
3134 InputContext->EP[Dci-1].CErr = 3;\r
3135 }\r
3136\r
3137 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] == NULL) {\r
3138 EndpointTransferRing = AllocateZeroPool (sizeof (TRANSFER_RING));\r
3139 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *)EndpointTransferRing;\r
3140 CreateTransferRing (Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
3141 DEBUG ((\r
3142 DEBUG_INFO,\r
3143 "Endpoint64[%x]: Created INT ring [%p~%p)\n",\r
3144 EpDesc->EndpointAddress,\r
3145 EndpointTransferRing->RingSeg0,\r
3146 (UINTN)EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
3147 ));\r
3148 }\r
3149\r
3150 break;\r
3151\r
3152 case USB_ENDPOINT_CONTROL:\r
3153 //\r
3154 // Do not support control transfer now.\r
3155 //\r
3156 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
3157 default:\r
3158 DEBUG ((DEBUG_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));\r
3159 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3160 continue;\r
3161 }\r
3162\r
3163 PhyAddr = UsbHcGetPciAddrForHostAddr (\r
3164 Xhc->MemPool,\r
3165 ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
3166 sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
3167 );\r
3168 PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
3169 PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
3170 InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3171 InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3172\r
3173 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3174 }\r
3175\r
3176 return MaxDci;\r
3177}\r
3178\r
3179/**\r
3180 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
3181\r
3182 @param Xhc The XHCI Instance.\r
3183 @param SlotId The slot id to be configured.\r
3184 @param DeviceSpeed The device's speed.\r
3185 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3186\r
3187 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
3188\r
3189**/\r
3190EFI_STATUS\r
3191EFIAPI\r
3192XhcSetConfigCmd (\r
3193 IN USB_XHCI_INSTANCE *Xhc,\r
3194 IN UINT8 SlotId,\r
3195 IN UINT8 DeviceSpeed,\r
3196 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
3197 )\r
3198{\r
3199 EFI_STATUS Status;\r
3200 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3201 UINT8 Index;\r
3202 UINT8 Dci;\r
3203 UINT8 MaxDci;\r
3204 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3205\r
3206 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3207 INPUT_CONTEXT *InputContext;\r
3208 DEVICE_CONTEXT *OutputContext;\r
3209 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3210\r
3211 //\r
3212 // 4.6.6 Configure Endpoint\r
3213 //\r
3214 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3215 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3216 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3217 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
3218\r
3219 ASSERT (ConfigDesc != NULL);\r
3220\r
3221 MaxDci = 0;\r
3222\r
3223 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3224 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
3225 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
3226 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3227 }\r
3228\r
3229 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
3230 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3231 continue;\r
3232 }\r
3233\r
3234 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
3235 if (Dci > MaxDci) {\r
3236 MaxDci = Dci;\r
3237 }\r
3238\r
3239 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3240 }\r
3241\r
3242 InputContext->InputControlContext.Dword2 |= BIT0;\r
3243 InputContext->Slot.ContextEntries = MaxDci;\r
3244 //\r
3245 // configure endpoint\r
3246 //\r
3247 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3248 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3249 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3250 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3251 CmdTrbCfgEP.CycleBit = 1;\r
3252 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3253 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3254 DEBUG ((DEBUG_INFO, "Configure Endpoint\n"));\r
3255 Status = XhcCmdTransfer (\r
3256 Xhc,\r
3257 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
3258 XHC_GENERIC_TIMEOUT,\r
3259 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3260 );\r
3261 if (EFI_ERROR (Status)) {\r
3262 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd: Config Endpoint Failed, Status = %r\n", Status));\r
3263 } else {\r
3264 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
3265 }\r
3266\r
3267 return Status;\r
3268}\r
3269\r
3270/**\r
3271 Configure all the device endpoints through XHCI's Configure_Endpoint cmd.\r
3272\r
3273 @param Xhc The XHCI Instance.\r
3274 @param SlotId The slot id to be configured.\r
3275 @param DeviceSpeed The device's speed.\r
3276 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3277\r
3278 @retval EFI_SUCCESS Successfully configure all the device endpoints.\r
3279\r
3280**/\r
3281EFI_STATUS\r
3282EFIAPI\r
3283XhcSetConfigCmd64 (\r
3284 IN USB_XHCI_INSTANCE *Xhc,\r
3285 IN UINT8 SlotId,\r
3286 IN UINT8 DeviceSpeed,\r
3287 IN USB_CONFIG_DESCRIPTOR *ConfigDesc\r
3288 )\r
3289{\r
3290 EFI_STATUS Status;\r
3291 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3292 UINT8 Index;\r
3293 UINT8 Dci;\r
3294 UINT8 MaxDci;\r
3295 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3296\r
3297 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3298 INPUT_CONTEXT_64 *InputContext;\r
3299 DEVICE_CONTEXT_64 *OutputContext;\r
3300 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3301\r
3302 //\r
3303 // 4.6.6 Configure Endpoint\r
3304 //\r
3305 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3306 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3307 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3308 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
3309\r
3310 ASSERT (ConfigDesc != NULL);\r
3311\r
3312 MaxDci = 0;\r
3313\r
3314 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3315 for (Index = 0; Index < ConfigDesc->NumInterfaces; Index++) {\r
3316 while ((IfDesc->DescriptorType != USB_DESC_TYPE_INTERFACE) || (IfDesc->AlternateSetting != 0)) {\r
3317 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3318 }\r
3319\r
3320 if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
3321 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3322 continue;\r
3323 }\r
3324\r
3325 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
3326 if (Dci > MaxDci) {\r
3327 MaxDci = Dci;\r
3328 }\r
3329\r
3330 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3331 }\r
3332\r
3333 InputContext->InputControlContext.Dword2 |= BIT0;\r
3334 InputContext->Slot.ContextEntries = MaxDci;\r
3335 //\r
3336 // configure endpoint\r
3337 //\r
3338 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3339 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3340 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3341 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3342 CmdTrbCfgEP.CycleBit = 1;\r
3343 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3344 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3345 DEBUG ((DEBUG_INFO, "Configure Endpoint\n"));\r
3346 Status = XhcCmdTransfer (\r
3347 Xhc,\r
3348 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
3349 XHC_GENERIC_TIMEOUT,\r
3350 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3351 );\r
3352 if (EFI_ERROR (Status)) {\r
3353 DEBUG ((DEBUG_ERROR, "XhcSetConfigCmd64: Config Endpoint Failed, Status = %r\n", Status));\r
3354 } else {\r
3355 Xhc->UsbDevContext[SlotId].ActiveConfiguration = ConfigDesc->ConfigurationValue;\r
3356 }\r
3357\r
3358 return Status;\r
3359}\r
3360\r
3361/**\r
3362 Stop endpoint through XHCI's Stop_Endpoint cmd.\r
3363\r
3364 @param Xhc The XHCI Instance.\r
3365 @param SlotId The slot id to be configured.\r
3366 @param Dci The device context index of endpoint.\r
3367 @param PendingUrb The pending URB to check completion status when stopping the end point.\r
3368\r
3369 @retval EFI_SUCCESS Stop endpoint successfully.\r
3370 @retval Others Failed to stop endpoint.\r
3371\r
3372**/\r
3373EFI_STATUS\r
3374EFIAPI\r
3375XhcStopEndpoint (\r
3376 IN USB_XHCI_INSTANCE *Xhc,\r
3377 IN UINT8 SlotId,\r
3378 IN UINT8 Dci,\r
3379 IN URB *PendingUrb OPTIONAL\r
3380 )\r
3381{\r
3382 EFI_STATUS Status;\r
3383 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3384 CMD_TRB_STOP_ENDPOINT CmdTrbStopED;\r
3385\r
3386 DEBUG ((DEBUG_VERBOSE, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
3387\r
3388 //\r
3389 // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks\r
3390 // the PendingUrb completion status, because it's possible that the PendingUrb is\r
3391 // finished just before stopping the end point, but after the looping check.\r
3392 //\r
3393 // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult\r
3394 // through function parameter, but That will cause every consumer of XhcCmdTransfer,\r
3395 // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.\r
3396 // But actually only XhcCheckUrbResult is aware of the PendingUrb.\r
3397 // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.\r
3398 //\r
3399 ASSERT (Xhc->PendingUrb == NULL);\r
3400 Xhc->PendingUrb = PendingUrb;\r
3401 //\r
3402 // Reset the URB result from Timeout to NoError.\r
3403 // The USB result will be:\r
3404 // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or\r
3405 // remain NoError when Success/ShortPacket Transfer Event is received.\r
3406 //\r
3407 if (PendingUrb != NULL) {\r
3408 PendingUrb->Result = EFI_USB_NOERROR;\r
3409 }\r
3410\r
3411 //\r
3412 // Send stop endpoint command to transit Endpoint from running to stop state\r
3413 //\r
3414 ZeroMem (&CmdTrbStopED, sizeof (CmdTrbStopED));\r
3415 CmdTrbStopED.CycleBit = 1;\r
3416 CmdTrbStopED.Type = TRB_TYPE_STOP_ENDPOINT;\r
3417 CmdTrbStopED.EDID = Dci;\r
3418 CmdTrbStopED.SlotId = SlotId;\r
3419 Status = XhcCmdTransfer (\r
3420 Xhc,\r
3421 (TRB_TEMPLATE *)(UINTN)&CmdTrbStopED,\r
3422 XHC_GENERIC_TIMEOUT,\r
3423 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3424 );\r
3425 if (EFI_ERROR (Status)) {\r
3426 DEBUG ((DEBUG_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
3427 }\r
3428\r
3429 Xhc->PendingUrb = NULL;\r
3430\r
3431 return Status;\r
3432}\r
3433\r
3434/**\r
3435 Reset endpoint through XHCI's Reset_Endpoint cmd.\r
3436\r
3437 @param Xhc The XHCI Instance.\r
3438 @param SlotId The slot id to be configured.\r
3439 @param Dci The device context index of endpoint.\r
3440\r
3441 @retval EFI_SUCCESS Reset endpoint successfully.\r
3442 @retval Others Failed to reset endpoint.\r
3443\r
3444**/\r
3445EFI_STATUS\r
3446EFIAPI\r
3447XhcResetEndpoint (\r
3448 IN USB_XHCI_INSTANCE *Xhc,\r
3449 IN UINT8 SlotId,\r
3450 IN UINT8 Dci\r
3451 )\r
3452{\r
3453 EFI_STATUS Status;\r
3454 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3455 CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
3456\r
3457 DEBUG ((DEBUG_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
3458\r
3459 //\r
3460 // Send stop endpoint command to transit Endpoint from running to stop state\r
3461 //\r
3462 ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
3463 CmdTrbResetED.CycleBit = 1;\r
3464 CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
3465 CmdTrbResetED.EDID = Dci;\r
3466 CmdTrbResetED.SlotId = SlotId;\r
3467 Status = XhcCmdTransfer (\r
3468 Xhc,\r
3469 (TRB_TEMPLATE *)(UINTN)&CmdTrbResetED,\r
3470 XHC_GENERIC_TIMEOUT,\r
3471 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3472 );\r
3473 if (EFI_ERROR (Status)) {\r
3474 DEBUG ((DEBUG_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
3475 }\r
3476\r
3477 return Status;\r
3478}\r
3479\r
3480/**\r
3481 Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
3482\r
3483 @param Xhc The XHCI Instance.\r
3484 @param SlotId The slot id to be configured.\r
3485 @param Dci The device context index of endpoint.\r
3486 @param Urb The dequeue pointer of the transfer ring specified\r
3487 by the urb to be updated.\r
3488\r
3489 @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.\r
3490 @retval Others Failed to set transfer ring dequeue pointer.\r
3491\r
3492**/\r
3493EFI_STATUS\r
3494EFIAPI\r
3495XhcSetTrDequeuePointer (\r
3496 IN USB_XHCI_INSTANCE *Xhc,\r
3497 IN UINT8 SlotId,\r
3498 IN UINT8 Dci,\r
3499 IN URB *Urb\r
3500 )\r
3501{\r
3502 EFI_STATUS Status;\r
3503 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3504 CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
3505 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3506\r
3507 DEBUG ((DEBUG_VERBOSE, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
3508\r
3509 //\r
3510 // Send stop endpoint command to transit Endpoint from running to stop state\r
3511 //\r
3512 ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
3513 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
3514 CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
3515 CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3516 CmdSetTRDeq.CycleBit = 1;\r
3517 CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
3518 CmdSetTRDeq.Endpoint = Dci;\r
3519 CmdSetTRDeq.SlotId = SlotId;\r
3520 Status = XhcCmdTransfer (\r
3521 Xhc,\r
3522 (TRB_TEMPLATE *)(UINTN)&CmdSetTRDeq,\r
3523 XHC_GENERIC_TIMEOUT,\r
3524 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3525 );\r
3526 if (EFI_ERROR (Status)) {\r
3527 DEBUG ((DEBUG_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
3528 }\r
3529\r
3530 return Status;\r
3531}\r
3532\r
3533/**\r
3534 Set interface through XHCI's Configure_Endpoint cmd.\r
3535\r
3536 @param Xhc The XHCI Instance.\r
3537 @param SlotId The slot id to be configured.\r
3538 @param DeviceSpeed The device's speed.\r
3539 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3540 @param Request USB device request to send.\r
3541\r
3542 @retval EFI_SUCCESS Successfully set interface.\r
3543\r
3544**/\r
3545EFI_STATUS\r
3546EFIAPI\r
3547XhcSetInterface (\r
3548 IN USB_XHCI_INSTANCE *Xhc,\r
3549 IN UINT8 SlotId,\r
3550 IN UINT8 DeviceSpeed,\r
3551 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3552 IN EFI_USB_DEVICE_REQUEST *Request\r
3553 )\r
3554{\r
3555 EFI_STATUS Status;\r
3556 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3557 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3558 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3559 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3560 UINTN NumEp;\r
3561 UINTN EpIndex;\r
3562 UINT8 EpAddr;\r
3563 UINT8 Direction;\r
3564 UINT8 Dci;\r
3565 UINT8 MaxDci;\r
3566 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3567 VOID *RingSeg;\r
3568\r
3569 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3570 INPUT_CONTEXT *InputContext;\r
3571 DEVICE_CONTEXT *OutputContext;\r
3572 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3573\r
3574 Status = EFI_SUCCESS;\r
3575\r
3576 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3577 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3578 //\r
3579 // XHCI 4.6.6 Configure Endpoint\r
3580 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3581 // Context and Add Context flags as follows:\r
3582 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3583 // Context and Add Context flags to '0'.\r
3584 //\r
3585 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3586 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3587 //\r
3588 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3589 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT));\r
3590\r
3591 ASSERT (ConfigDesc != NULL);\r
3592\r
3593 MaxDci = 0;\r
3594\r
3595 IfDescActive = NULL;\r
3596 IfDescSet = NULL;\r
3597\r
3598 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3599 while ((UINTN)IfDesc < ((UINTN)ConfigDesc + ConfigDesc->TotalLength)) {\r
3600 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
3601 if (IfDesc->InterfaceNumber == (UINT8)Request->Index) {\r
3602 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3603 //\r
3604 // Find out the active interface descriptor.\r
3605 //\r
3606 IfDescActive = IfDesc;\r
3607 } else if (IfDesc->AlternateSetting == (UINT8)Request->Value) {\r
3608 //\r
3609 // Find out the interface descriptor to set.\r
3610 //\r
3611 IfDescSet = IfDesc;\r
3612 }\r
3613 }\r
3614 }\r
3615\r
3616 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3617 }\r
3618\r
3619 //\r
3620 // XHCI 4.6.6 Configure Endpoint\r
3621 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3622 // Context and Add Context flags as follows:\r
3623 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3624 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3625 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3626 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3627 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3628 // and Add Context flags shall be set to '1'.\r
3629 //\r
3630 // Below codes are to cover 2), 3) and 4).\r
3631 //\r
3632\r
3633 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3634 NumEp = IfDescActive->NumEndpoints;\r
3635 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDescActive + 1);\r
3636 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3637 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3638 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3639 }\r
3640\r
3641 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3642 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3643 continue;\r
3644 }\r
3645\r
3646 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
3647 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3648\r
3649 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3650 ASSERT (Dci < 32);\r
3651 if (Dci > MaxDci) {\r
3652 MaxDci = Dci;\r
3653 }\r
3654\r
3655 //\r
3656 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3657 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3658 //\r
3659 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
3660 if (EFI_ERROR (Status)) {\r
3661 return Status;\r
3662 }\r
3663\r
3664 //\r
3665 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3666 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3667 //\r
3668 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3669 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3670 if (RingSeg != NULL) {\r
3671 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3672 }\r
3673\r
3674 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3675 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3676 }\r
3677\r
3678 //\r
3679 // Set the Drop Context flag to '1'.\r
3680 //\r
3681 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3682\r
3683 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3684 }\r
3685\r
3686 //\r
3687 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3688 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3689 // Interface setting, to '0'.\r
3690 //\r
3691 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3692 //\r
3693\r
3694 //\r
3695 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3696 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3697 // a. Allocate a Transfer Ring.\r
3698 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3699 // c. Initialize the Endpoint Context data structure.\r
3700 //\r
3701 Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3702 if (Dci > MaxDci) {\r
3703 MaxDci = Dci;\r
3704 }\r
3705\r
3706 InputContext->InputControlContext.Dword2 |= BIT0;\r
3707 InputContext->Slot.ContextEntries = MaxDci;\r
3708 //\r
3709 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3710 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3711 //\r
3712 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3713 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3714 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3715 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3716 CmdTrbCfgEP.CycleBit = 1;\r
3717 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3718 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3719 DEBUG ((DEBUG_INFO, "SetInterface: Configure Endpoint\n"));\r
3720 Status = XhcCmdTransfer (\r
3721 Xhc,\r
3722 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
3723 XHC_GENERIC_TIMEOUT,\r
3724 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3725 );\r
3726 if (EFI_ERROR (Status)) {\r
3727 DEBUG ((DEBUG_ERROR, "SetInterface: Config Endpoint Failed, Status = %r\n", Status));\r
3728 } else {\r
3729 //\r
3730 // Update the active AlternateSetting.\r
3731 //\r
3732 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8)Request->Index] = (UINT8)Request->Value;\r
3733 }\r
3734 }\r
3735\r
3736 return Status;\r
3737}\r
3738\r
3739/**\r
3740 Set interface through XHCI's Configure_Endpoint cmd.\r
3741\r
3742 @param Xhc The XHCI Instance.\r
3743 @param SlotId The slot id to be configured.\r
3744 @param DeviceSpeed The device's speed.\r
3745 @param ConfigDesc The pointer to the usb device configuration descriptor.\r
3746 @param Request USB device request to send.\r
3747\r
3748 @retval EFI_SUCCESS Successfully set interface.\r
3749\r
3750**/\r
3751EFI_STATUS\r
3752EFIAPI\r
3753XhcSetInterface64 (\r
3754 IN USB_XHCI_INSTANCE *Xhc,\r
3755 IN UINT8 SlotId,\r
3756 IN UINT8 DeviceSpeed,\r
3757 IN USB_CONFIG_DESCRIPTOR *ConfigDesc,\r
3758 IN EFI_USB_DEVICE_REQUEST *Request\r
3759 )\r
3760{\r
3761 EFI_STATUS Status;\r
3762 USB_INTERFACE_DESCRIPTOR *IfDescActive;\r
3763 USB_INTERFACE_DESCRIPTOR *IfDescSet;\r
3764 USB_INTERFACE_DESCRIPTOR *IfDesc;\r
3765 USB_ENDPOINT_DESCRIPTOR *EpDesc;\r
3766 UINTN NumEp;\r
3767 UINTN EpIndex;\r
3768 UINT8 EpAddr;\r
3769 UINT8 Direction;\r
3770 UINT8 Dci;\r
3771 UINT8 MaxDci;\r
3772 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3773 VOID *RingSeg;\r
3774\r
3775 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
3776 INPUT_CONTEXT_64 *InputContext;\r
3777 DEVICE_CONTEXT_64 *OutputContext;\r
3778 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3779\r
3780 Status = EFI_SUCCESS;\r
3781\r
3782 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3783 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3784 //\r
3785 // XHCI 4.6.6 Configure Endpoint\r
3786 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3787 // Context and Add Context flags as follows:\r
3788 // 1) If an endpoint is not modified by the Alternate Interface setting, then software shall set the Drop\r
3789 // Context and Add Context flags to '0'.\r
3790 //\r
3791 // Except the interface indicated by Reqeust->Index, no impact to other interfaces.\r
3792 // So the default Drop Context and Add Context flags can be '0' to cover 1).\r
3793 //\r
3794 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
3795 CopyMem (&InputContext->Slot, &OutputContext->Slot, sizeof (SLOT_CONTEXT_64));\r
3796\r
3797 ASSERT (ConfigDesc != NULL);\r
3798\r
3799 MaxDci = 0;\r
3800\r
3801 IfDescActive = NULL;\r
3802 IfDescSet = NULL;\r
3803\r
3804 IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
3805 while ((UINTN)IfDesc < ((UINTN)ConfigDesc + ConfigDesc->TotalLength)) {\r
3806 if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
3807 if (IfDesc->InterfaceNumber == (UINT8)Request->Index) {\r
3808 if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
3809 //\r
3810 // Find out the active interface descriptor.\r
3811 //\r
3812 IfDescActive = IfDesc;\r
3813 } else if (IfDesc->AlternateSetting == (UINT8)Request->Value) {\r
3814 //\r
3815 // Find out the interface descriptor to set.\r
3816 //\r
3817 IfDescSet = IfDesc;\r
3818 }\r
3819 }\r
3820 }\r
3821\r
3822 IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
3823 }\r
3824\r
3825 //\r
3826 // XHCI 4.6.6 Configure Endpoint\r
3827 // When this command is used to "Set an Alternate Interface on a device", software shall set the Drop\r
3828 // Context and Add Context flags as follows:\r
3829 // 2) If an endpoint previously disabled, is enabled by the Alternate Interface setting, then software shall set\r
3830 // the Drop Context flag to '0' and Add Context flag to '1', and initialize the Input Endpoint Context.\r
3831 // 3) If an endpoint previously enabled, is disabled by the Alternate Interface setting, then software shall set\r
3832 // the Drop Context flag to '1' and Add Context flag to '0'.\r
3833 // 4) If a parameter of an enabled endpoint is modified by an Alternate Interface setting, the Drop Context\r
3834 // and Add Context flags shall be set to '1'.\r
3835 //\r
3836 // Below codes are to cover 2), 3) and 4).\r
3837 //\r
3838\r
3839 if ((IfDescActive != NULL) && (IfDescSet != NULL)) {\r
3840 NumEp = IfDescActive->NumEndpoints;\r
3841 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)(IfDescActive + 1);\r
3842 for (EpIndex = 0; EpIndex < NumEp; EpIndex++) {\r
3843 while (EpDesc->DescriptorType != USB_DESC_TYPE_ENDPOINT) {\r
3844 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3845 }\r
3846\r
3847 if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
3848 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3849 continue;\r
3850 }\r
3851\r
3852 EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
3853 Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
3854\r
3855 Dci = XhcEndpointToDci (EpAddr, Direction);\r
3856 ASSERT (Dci < 32);\r
3857 if (Dci > MaxDci) {\r
3858 MaxDci = Dci;\r
3859 }\r
3860\r
3861 //\r
3862 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3863 // 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
3864 //\r
3865 Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
3866 if (EFI_ERROR (Status)) {\r
3867 return Status;\r
3868 }\r
3869\r
3870 //\r
3871 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3872 // 2) Free Transfer Rings of all endpoints that will be affected by the Alternate Interface setting.\r
3873 //\r
3874 if (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] != NULL) {\r
3875 RingSeg = ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1])->RingSeg0;\r
3876 if (RingSeg != NULL) {\r
3877 UsbHcFreeMem (Xhc->MemPool, RingSeg, sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER);\r
3878 }\r
3879\r
3880 FreePool (Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1]);\r
3881 Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci - 1] = NULL;\r
3882 }\r
3883\r
3884 //\r
3885 // Set the Drop Context flag to '1'.\r
3886 //\r
3887 InputContext->InputControlContext.Dword1 |= (BIT0 << Dci);\r
3888\r
3889 EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
3890 }\r
3891\r
3892 //\r
3893 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3894 // 3) Clear all the Endpoint Context fields of each endpoint that will be disabled by the Alternate\r
3895 // Interface setting, to '0'.\r
3896 //\r
3897 // The step 3) has been covered by the ZeroMem () to InputContext at the start of the function.\r
3898 //\r
3899\r
3900 //\r
3901 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3902 // 4) For each endpoint enabled by the Configure Endpoint Command:\r
3903 // a. Allocate a Transfer Ring.\r
3904 // b. Initialize the Transfer Ring Segment(s) by clearing all fields of all TRBs to '0'.\r
3905 // c. Initialize the Endpoint Context data structure.\r
3906 //\r
3907 Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDescSet);\r
3908 if (Dci > MaxDci) {\r
3909 MaxDci = Dci;\r
3910 }\r
3911\r
3912 InputContext->InputControlContext.Dword2 |= BIT0;\r
3913 InputContext->Slot.ContextEntries = MaxDci;\r
3914 //\r
3915 // XHCI 4.3.6 - Setting Alternate Interfaces\r
3916 // 5) Issue and successfully complete a Configure Endpoint Command.\r
3917 //\r
3918 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
3919 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
3920 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3921 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3922 CmdTrbCfgEP.CycleBit = 1;\r
3923 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
3924 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3925 DEBUG ((DEBUG_INFO, "SetInterface64: Configure Endpoint\n"));\r
3926 Status = XhcCmdTransfer (\r
3927 Xhc,\r
3928 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
3929 XHC_GENERIC_TIMEOUT,\r
3930 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3931 );\r
3932 if (EFI_ERROR (Status)) {\r
3933 DEBUG ((DEBUG_ERROR, "SetInterface64: Config Endpoint Failed, Status = %r\n", Status));\r
3934 } else {\r
3935 //\r
3936 // Update the active AlternateSetting.\r
3937 //\r
3938 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8)Request->Index] = (UINT8)Request->Value;\r
3939 }\r
3940 }\r
3941\r
3942 return Status;\r
3943}\r
3944\r
3945/**\r
3946 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
3947\r
3948 @param Xhc The XHCI Instance.\r
3949 @param SlotId The slot id to be evaluated.\r
3950 @param MaxPacketSize The max packet size supported by the device control transfer.\r
3951\r
3952 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
3953\r
3954**/\r
3955EFI_STATUS\r
3956EFIAPI\r
3957XhcEvaluateContext (\r
3958 IN USB_XHCI_INSTANCE *Xhc,\r
3959 IN UINT8 SlotId,\r
3960 IN UINT32 MaxPacketSize\r
3961 )\r
3962{\r
3963 EFI_STATUS Status;\r
3964 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
3965 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
3966 INPUT_CONTEXT *InputContext;\r
3967 DEVICE_CONTEXT *OutputContext;\r
3968 EFI_PHYSICAL_ADDRESS PhyAddr;\r
3969\r
3970 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
3971\r
3972 //\r
3973 // 4.6.7 Evaluate Context\r
3974 //\r
3975 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
3976 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
3977 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
3978\r
3979 CopyMem (&InputContext->EP[0], &OutputContext->EP[0], sizeof (ENDPOINT_CONTEXT));\r
3980\r
3981 InputContext->InputControlContext.Dword2 |= BIT1;\r
3982 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
3983 InputContext->EP[0].EPState = 0;\r
3984\r
3985 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
3986 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
3987 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
3988 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
3989 CmdTrbEvalu.CycleBit = 1;\r
3990 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
3991 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
3992 DEBUG ((DEBUG_INFO, "Evaluate context\n"));\r
3993 Status = XhcCmdTransfer (\r
3994 Xhc,\r
3995 (TRB_TEMPLATE *)(UINTN)&CmdTrbEvalu,\r
3996 XHC_GENERIC_TIMEOUT,\r
3997 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
3998 );\r
3999 if (EFI_ERROR (Status)) {\r
4000 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext: Evaluate Context Failed, Status = %r\n", Status));\r
4001 }\r
4002\r
4003 return Status;\r
4004}\r
4005\r
4006/**\r
4007 Evaluate the endpoint 0 context through XHCI's Evaluate_Context cmd.\r
4008\r
4009 @param Xhc The XHCI Instance.\r
4010 @param SlotId The slot id to be evaluated.\r
4011 @param MaxPacketSize The max packet size supported by the device control transfer.\r
4012\r
4013 @retval EFI_SUCCESS Successfully evaluate the device endpoint 0.\r
4014\r
4015**/\r
4016EFI_STATUS\r
4017EFIAPI\r
4018XhcEvaluateContext64 (\r
4019 IN USB_XHCI_INSTANCE *Xhc,\r
4020 IN UINT8 SlotId,\r
4021 IN UINT32 MaxPacketSize\r
4022 )\r
4023{\r
4024 EFI_STATUS Status;\r
4025 CMD_TRB_EVALUATE_CONTEXT CmdTrbEvalu;\r
4026 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
4027 INPUT_CONTEXT_64 *InputContext;\r
4028 DEVICE_CONTEXT_64 *OutputContext;\r
4029 EFI_PHYSICAL_ADDRESS PhyAddr;\r
4030\r
4031 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
4032\r
4033 //\r
4034 // 4.6.7 Evaluate Context\r
4035 //\r
4036 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
4037 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
4038 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
4039\r
4040 CopyMem (&InputContext->EP[0], &OutputContext->EP[0], sizeof (ENDPOINT_CONTEXT_64));\r
4041\r
4042 InputContext->InputControlContext.Dword2 |= BIT1;\r
4043 InputContext->EP[0].MaxPacketSize = MaxPacketSize;\r
4044 InputContext->EP[0].EPState = 0;\r
4045\r
4046 ZeroMem (&CmdTrbEvalu, sizeof (CmdTrbEvalu));\r
4047 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
4048 CmdTrbEvalu.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
4049 CmdTrbEvalu.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
4050 CmdTrbEvalu.CycleBit = 1;\r
4051 CmdTrbEvalu.Type = TRB_TYPE_EVALU_CONTXT;\r
4052 CmdTrbEvalu.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
4053 DEBUG ((DEBUG_INFO, "Evaluate context\n"));\r
4054 Status = XhcCmdTransfer (\r
4055 Xhc,\r
4056 (TRB_TEMPLATE *)(UINTN)&CmdTrbEvalu,\r
4057 XHC_GENERIC_TIMEOUT,\r
4058 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
4059 );\r
4060 if (EFI_ERROR (Status)) {\r
4061 DEBUG ((DEBUG_ERROR, "XhcEvaluateContext64: Evaluate Context Failed, Status = %r\n", Status));\r
4062 }\r
4063\r
4064 return Status;\r
4065}\r
4066\r
4067/**\r
4068 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
4069\r
4070 @param Xhc The XHCI Instance.\r
4071 @param SlotId The slot id to be configured.\r
4072 @param PortNum The total number of downstream port supported by the hub.\r
4073 @param TTT The TT think time of the hub device.\r
4074 @param MTT The multi-TT of the hub device.\r
4075\r
4076 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
4077\r
4078**/\r
4079EFI_STATUS\r
4080XhcConfigHubContext (\r
4081 IN USB_XHCI_INSTANCE *Xhc,\r
4082 IN UINT8 SlotId,\r
4083 IN UINT8 PortNum,\r
4084 IN UINT8 TTT,\r
4085 IN UINT8 MTT\r
4086 )\r
4087{\r
4088 EFI_STATUS Status;\r
4089 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
4090 INPUT_CONTEXT *InputContext;\r
4091 DEVICE_CONTEXT *OutputContext;\r
4092 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
4093 EFI_PHYSICAL_ADDRESS PhyAddr;\r
4094\r
4095 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
4096 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
4097 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
4098\r
4099 //\r
4100 // 4.6.7 Evaluate Context\r
4101 //\r
4102 ZeroMem (InputContext, sizeof (INPUT_CONTEXT));\r
4103\r
4104 InputContext->InputControlContext.Dword2 |= BIT0;\r
4105\r
4106 //\r
4107 // Copy the slot context from OutputContext to Input context\r
4108 //\r
4109 CopyMem (&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT));\r
4110 InputContext->Slot.Hub = 1;\r
4111 InputContext->Slot.PortNum = PortNum;\r
4112 InputContext->Slot.TTT = TTT;\r
4113 InputContext->Slot.MTT = MTT;\r
4114\r
4115 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
4116 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT));\r
4117 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
4118 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
4119 CmdTrbCfgEP.CycleBit = 1;\r
4120 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
4121 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
4122 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context\n"));\r
4123 Status = XhcCmdTransfer (\r
4124 Xhc,\r
4125 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
4126 XHC_GENERIC_TIMEOUT,\r
4127 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
4128 );\r
4129 if (EFI_ERROR (Status)) {\r
4130 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext: Config Endpoint Failed, Status = %r\n", Status));\r
4131 }\r
4132\r
4133 return Status;\r
4134}\r
4135\r
4136/**\r
4137 Evaluate the slot context for hub device through XHCI's Configure_Endpoint cmd.\r
4138\r
4139 @param Xhc The XHCI Instance.\r
4140 @param SlotId The slot id to be configured.\r
4141 @param PortNum The total number of downstream port supported by the hub.\r
4142 @param TTT The TT think time of the hub device.\r
4143 @param MTT The multi-TT of the hub device.\r
4144\r
4145 @retval EFI_SUCCESS Successfully configure the hub device's slot context.\r
4146\r
4147**/\r
4148EFI_STATUS\r
4149XhcConfigHubContext64 (\r
4150 IN USB_XHCI_INSTANCE *Xhc,\r
4151 IN UINT8 SlotId,\r
4152 IN UINT8 PortNum,\r
4153 IN UINT8 TTT,\r
4154 IN UINT8 MTT\r
4155 )\r
4156{\r
4157 EFI_STATUS Status;\r
4158 EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
4159 INPUT_CONTEXT_64 *InputContext;\r
4160 DEVICE_CONTEXT_64 *OutputContext;\r
4161 CMD_TRB_CONFIG_ENDPOINT CmdTrbCfgEP;\r
4162 EFI_PHYSICAL_ADDRESS PhyAddr;\r
4163\r
4164 ASSERT (Xhc->UsbDevContext[SlotId].SlotId != 0);\r
4165 InputContext = Xhc->UsbDevContext[SlotId].InputContext;\r
4166 OutputContext = Xhc->UsbDevContext[SlotId].OutputContext;\r
4167\r
4168 //\r
4169 // 4.6.7 Evaluate Context\r
4170 //\r
4171 ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));\r
4172\r
4173 InputContext->InputControlContext.Dword2 |= BIT0;\r
4174\r
4175 //\r
4176 // Copy the slot context from OutputContext to Input context\r
4177 //\r
4178 CopyMem (&(InputContext->Slot), &(OutputContext->Slot), sizeof (SLOT_CONTEXT_64));\r
4179 InputContext->Slot.Hub = 1;\r
4180 InputContext->Slot.PortNum = PortNum;\r
4181 InputContext->Slot.TTT = TTT;\r
4182 InputContext->Slot.MTT = MTT;\r
4183\r
4184 ZeroMem (&CmdTrbCfgEP, sizeof (CmdTrbCfgEP));\r
4185 PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, InputContext, sizeof (INPUT_CONTEXT_64));\r
4186 CmdTrbCfgEP.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
4187 CmdTrbCfgEP.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
4188 CmdTrbCfgEP.CycleBit = 1;\r
4189 CmdTrbCfgEP.Type = TRB_TYPE_CON_ENDPOINT;\r
4190 CmdTrbCfgEP.SlotId = Xhc->UsbDevContext[SlotId].SlotId;\r
4191 DEBUG ((DEBUG_INFO, "Configure Hub Slot Context\n"));\r
4192 Status = XhcCmdTransfer (\r
4193 Xhc,\r
4194 (TRB_TEMPLATE *)(UINTN)&CmdTrbCfgEP,\r
4195 XHC_GENERIC_TIMEOUT,\r
4196 (TRB_TEMPLATE **)(UINTN)&EvtTrb\r
4197 );\r
4198 if (EFI_ERROR (Status)) {\r
4199 DEBUG ((DEBUG_ERROR, "XhcConfigHubContext64: Config Endpoint Failed, Status = %r\n", Status));\r
4200 }\r
4201\r
4202 return Status;\r
4203}\r