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