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