]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
MdeModulePkg/Xhci: Remove TDs from transfer ring when timeout happens
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciPei / XhcPeim.c
CommitLineData
d987459f
SZ
1/** @file\r
2PEIM to produce gPeiUsb2HostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
3which is used to enable recovery function from USB Drivers.\r
4\r
26cd2d6d 5Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
d987459f
SZ
6\r
7This program and the accompanying materials\r
8are licensed and made available under the terms and conditions\r
9of the BSD License which accompanies this distribution. The\r
10full text of the license may be found at\r
11http://opensource.org/licenses/bsd-license.php\r
12\r
13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include "XhcPeim.h"\r
19\r
20//\r
21// Two arrays used to translate the XHCI port state (change)\r
22// to the UEFI protocol's port state (change).\r
23//\r
24USB_PORT_STATE_MAP mUsbPortStateMap[] = {\r
25 {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION},\r
26 {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE},\r
27 {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},\r
28 {XHC_PORTSC_PP, USB_PORT_STAT_POWER},\r
29 {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}\r
30};\r
31\r
32USB_PORT_STATE_MAP mUsbPortChangeMap[] = {\r
33 {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
34 {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
35 {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
36 {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
37};\r
38\r
39USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {\r
40 {XHC_PORTSC_CSC, EfiUsbPortConnectChange},\r
41 {XHC_PORTSC_PEC, EfiUsbPortEnableChange},\r
42 {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
43 {XHC_PORTSC_PRC, EfiUsbPortResetChange}\r
44};\r
45\r
46USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {\r
47 {XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION},\r
48 {XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE},\r
49 {XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},\r
50 {XHC_HUB_PORTSC_PP, USB_PORT_STAT_POWER},\r
51 {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}\r
52};\r
53\r
54USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {\r
55 {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},\r
56 {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},\r
57 {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},\r
58 {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}\r
59};\r
60\r
61USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {\r
62 {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},\r
63 {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},\r
64 {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},\r
65 {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},\r
66 {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}\r
67};\r
68\r
69/**\r
70 Read XHCI Operation register.\r
71\r
72 @param Xhc The XHCI device.\r
73 @param Offset The operation register offset.\r
74\r
75 @retval the register content read.\r
76\r
77**/\r
78UINT32\r
79XhcPeiReadOpReg (\r
80 IN PEI_XHC_DEV *Xhc,\r
81 IN UINT32 Offset\r
82 )\r
83{\r
84 UINT32 Data;\r
85\r
86 ASSERT (Xhc->CapLength != 0);\r
87\r
88 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset);\r
89 return Data;\r
90}\r
91\r
92/**\r
93 Write the data to the XHCI operation register.\r
94\r
95 @param Xhc The XHCI device.\r
96 @param Offset The operation register offset.\r
97 @param Data The data to write.\r
98\r
99**/\r
100VOID\r
101XhcPeiWriteOpReg (\r
102 IN PEI_XHC_DEV *Xhc,\r
103 IN UINT32 Offset,\r
104 IN UINT32 Data\r
105 )\r
106{\r
107 ASSERT (Xhc->CapLength != 0);\r
108\r
109 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->CapLength + Offset, Data);\r
110}\r
111\r
112/**\r
113 Set one bit of the operational register while keeping other bits.\r
114\r
115 @param Xhc The XHCI device.\r
116 @param Offset The offset of the operational register.\r
117 @param Bit The bit mask of the register to set.\r
118\r
119**/\r
120VOID\r
121XhcPeiSetOpRegBit (\r
122 IN PEI_XHC_DEV *Xhc,\r
123 IN UINT32 Offset,\r
124 IN UINT32 Bit\r
125 )\r
126{\r
127 UINT32 Data;\r
128\r
129 Data = XhcPeiReadOpReg (Xhc, Offset);\r
130 Data |= Bit;\r
131 XhcPeiWriteOpReg (Xhc, Offset, Data);\r
132}\r
133\r
134/**\r
135 Clear one bit of the operational register while keeping other bits.\r
136\r
137 @param Xhc The XHCI device.\r
138 @param Offset The offset of the operational register.\r
139 @param Bit The bit mask of the register to clear.\r
140\r
141**/\r
142VOID\r
143XhcPeiClearOpRegBit (\r
144 IN PEI_XHC_DEV *Xhc,\r
145 IN UINT32 Offset,\r
146 IN UINT32 Bit\r
147 )\r
148{\r
149 UINT32 Data;\r
150\r
151 Data = XhcPeiReadOpReg (Xhc, Offset);\r
152 Data &= ~Bit;\r
153 XhcPeiWriteOpReg (Xhc, Offset, Data);\r
154}\r
155\r
156/**\r
157 Wait the operation register's bit as specified by Bit\r
158 to become set (or clear).\r
159\r
160 @param Xhc The XHCI device.\r
161 @param Offset The offset of the operational register.\r
162 @param Bit The bit mask of the register to wait for.\r
163 @param WaitToSet Wait the bit to set or clear.\r
26cd2d6d 164 @param Timeout The time to wait before abort (in millisecond, ms).\r
d987459f
SZ
165\r
166 @retval EFI_SUCCESS The bit successfully changed by host controller.\r
167 @retval EFI_TIMEOUT The time out occurred.\r
168\r
169**/\r
170EFI_STATUS\r
171XhcPeiWaitOpRegBit (\r
172 IN PEI_XHC_DEV *Xhc,\r
173 IN UINT32 Offset,\r
174 IN UINT32 Bit,\r
175 IN BOOLEAN WaitToSet,\r
176 IN UINT32 Timeout\r
177 )\r
178{\r
26cd2d6d 179 UINT64 Index;\r
d987459f 180\r
26cd2d6d 181 for (Index = 0; Index < Timeout * XHC_1_MILLISECOND; Index++) {\r
d987459f
SZ
182 if (XHC_REG_BIT_IS_SET (Xhc, Offset, Bit) == WaitToSet) {\r
183 return EFI_SUCCESS;\r
184 }\r
185\r
26cd2d6d 186 MicroSecondDelay (XHC_1_MICROSECOND);\r
d987459f
SZ
187 }\r
188\r
189 return EFI_TIMEOUT;\r
190}\r
191\r
192/**\r
193 Read XHCI capability register.\r
194\r
195 @param Xhc The XHCI device.\r
196 @param Offset Capability register address.\r
197\r
198 @retval the register content read.\r
199\r
200**/\r
201UINT32\r
202XhcPeiReadCapRegister (\r
203 IN PEI_XHC_DEV *Xhc,\r
204 IN UINT32 Offset\r
205 )\r
206{\r
207 UINT32 Data;\r
208\r
209 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Offset);\r
210\r
211 return Data;\r
212}\r
213\r
214/**\r
215 Read XHCI door bell register.\r
216\r
217 @param Xhc The XHCI device.\r
218 @param Offset The offset of the door bell register.\r
219\r
220 @return The register content read\r
221\r
222**/\r
223UINT32\r
224XhcPeiReadDoorBellReg (\r
225 IN PEI_XHC_DEV *Xhc,\r
226 IN UINT32 Offset\r
227 )\r
228{\r
229 UINT32 Data;\r
230\r
231 ASSERT (Xhc->DBOff != 0);\r
232\r
233 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset);\r
234\r
235 return Data;\r
236}\r
237\r
238/**\r
239 Write the data to the XHCI door bell register.\r
240\r
241 @param Xhc The XHCI device.\r
242 @param Offset The offset of the door bell register.\r
243 @param Data The data to write.\r
244\r
245**/\r
246VOID\r
247XhcPeiWriteDoorBellReg (\r
248 IN PEI_XHC_DEV *Xhc,\r
249 IN UINT32 Offset,\r
250 IN UINT32 Data\r
251 )\r
252{\r
253 ASSERT (Xhc->DBOff != 0);\r
254\r
255 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->DBOff + Offset, Data);\r
256}\r
257\r
258/**\r
259 Read XHCI runtime register.\r
260\r
261 @param Xhc The XHCI device.\r
262 @param Offset The offset of the runtime register.\r
263\r
264 @return The register content read\r
265\r
266**/\r
267UINT32\r
268XhcPeiReadRuntimeReg (\r
269 IN PEI_XHC_DEV *Xhc,\r
270 IN UINT32 Offset\r
271 )\r
272{\r
273 UINT32 Data;\r
274\r
275 ASSERT (Xhc->RTSOff != 0);\r
276\r
277 Data = MmioRead32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset);\r
278\r
279 return Data;\r
280}\r
281\r
282/**\r
283 Write the data to the XHCI runtime register.\r
284\r
285 @param Xhc The XHCI device.\r
286 @param Offset The offset of the runtime register.\r
287 @param Data The data to write.\r
288\r
289**/\r
290VOID\r
291XhcPeiWriteRuntimeReg (\r
292 IN PEI_XHC_DEV *Xhc,\r
293 IN UINT32 Offset,\r
294 IN UINT32 Data\r
295 )\r
296{\r
297 ASSERT (Xhc->RTSOff != 0);\r
298\r
299 MmioWrite32 (Xhc->UsbHostControllerBaseAddress + Xhc->RTSOff + Offset, Data);\r
300}\r
301\r
302/**\r
303 Set one bit of the runtime register while keeping other bits.\r
304\r
305 @param Xhc The XHCI device.\r
306 @param Offset The offset of the runtime register.\r
307 @param Bit The bit mask of the register to set.\r
308\r
309**/\r
310VOID\r
311XhcPeiSetRuntimeRegBit (\r
312 IN PEI_XHC_DEV *Xhc,\r
313 IN UINT32 Offset,\r
314 IN UINT32 Bit\r
315 )\r
316{\r
317 UINT32 Data;\r
318\r
319 Data = XhcPeiReadRuntimeReg (Xhc, Offset);\r
320 Data |= Bit;\r
321 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
322}\r
323\r
324/**\r
325 Clear one bit of the runtime register while keeping other bits.\r
326\r
327 @param Xhc The XHCI device.\r
328 @param Offset The offset of the runtime register.\r
329 @param Bit The bit mask of the register to set.\r
330\r
331**/\r
332VOID\r
333XhcPeiClearRuntimeRegBit (\r
334 IN PEI_XHC_DEV *Xhc,\r
335 IN UINT32 Offset,\r
336 IN UINT32 Bit\r
337 )\r
338{\r
339 UINT32 Data;\r
340\r
341 Data = XhcPeiReadRuntimeReg (Xhc, Offset);\r
342 Data &= ~Bit;\r
343 XhcPeiWriteRuntimeReg (Xhc, Offset, Data);\r
344}\r
345\r
346/**\r
347 Check whether Xhc is halted.\r
348\r
349 @param Xhc The XHCI device.\r
350\r
351 @retval TRUE The controller is halted.\r
352 @retval FALSE The controller isn't halted.\r
353\r
354**/\r
355BOOLEAN\r
356XhcPeiIsHalt (\r
357 IN PEI_XHC_DEV *Xhc\r
358 )\r
359{\r
360 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT);\r
361}\r
362\r
363/**\r
364 Check whether system error occurred.\r
365\r
366 @param Xhc The XHCI device.\r
367\r
368 @retval TRUE System error happened.\r
369 @retval FALSE No system error.\r
370\r
371**/\r
372BOOLEAN\r
373XhcPeiIsSysError (\r
374 IN PEI_XHC_DEV *Xhc\r
375 )\r
376{\r
377 return XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE);\r
378}\r
379\r
380/**\r
381 Reset the host controller.\r
382\r
383 @param Xhc The XHCI device.\r
26cd2d6d 384 @param Timeout Time to wait before abort (in millisecond, ms).\r
d987459f
SZ
385\r
386 @retval EFI_TIMEOUT The transfer failed due to time out.\r
387 @retval Others Failed to reset the host.\r
388\r
389**/\r
390EFI_STATUS\r
391XhcPeiResetHC (\r
392 IN PEI_XHC_DEV *Xhc,\r
393 IN UINT32 Timeout\r
394 )\r
395{\r
396 EFI_STATUS Status;\r
397\r
398 //\r
399 // Host can only be reset when it is halt. If not so, halt it\r
400 //\r
401 if (!XhcPeiIsHalt (Xhc)) {\r
402 Status = XhcPeiHaltHC (Xhc, Timeout);\r
403\r
404 if (EFI_ERROR (Status)) {\r
405 goto ON_EXIT;\r
406 }\r
407 }\r
408\r
409 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET);\r
410 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);\r
411ON_EXIT:\r
412 DEBUG ((EFI_D_INFO, "XhcPeiResetHC: %r\n", Status));\r
413 return Status;\r
414}\r
415\r
416/**\r
417 Halt the host controller.\r
418\r
419 @param Xhc The XHCI device.\r
420 @param Timeout Time to wait before abort.\r
421\r
422 @retval EFI_TIMEOUT Failed to halt the controller before Timeout.\r
423 @retval EFI_SUCCESS The XHCI is halt.\r
424\r
425**/\r
426EFI_STATUS\r
427XhcPeiHaltHC (\r
428 IN PEI_XHC_DEV *Xhc,\r
429 IN UINT32 Timeout\r
430 )\r
431{\r
432 EFI_STATUS Status;\r
433\r
434 XhcPeiClearOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
435 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, TRUE, Timeout);\r
436 DEBUG ((EFI_D_INFO, "XhcPeiHaltHC: %r\n", Status));\r
437 return Status;\r
438}\r
439\r
440/**\r
441 Set the XHCI to run.\r
442\r
443 @param Xhc The XHCI device.\r
444 @param Timeout Time to wait before abort.\r
445\r
446 @retval EFI_SUCCESS The XHCI is running.\r
447 @retval Others Failed to set the XHCI to run.\r
448\r
449**/\r
450EFI_STATUS\r
451XhcPeiRunHC (\r
452 IN PEI_XHC_DEV *Xhc,\r
453 IN UINT32 Timeout\r
454 )\r
455{\r
456 EFI_STATUS Status;\r
457\r
458 XhcPeiSetOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RUN);\r
459 Status = XhcPeiWaitOpRegBit (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT, FALSE, Timeout);\r
460 DEBUG ((EFI_D_INFO, "XhcPeiRunHC: %r\n", Status));\r
461 return Status;\r
462}\r
463\r
464/**\r
465 Submits control transfer to a target USB device.\r
466\r
467 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
468 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
469 @param DeviceAddress The target device address.\r
470 @param DeviceSpeed Target device speed.\r
471 @param MaximumPacketLength Maximum packet size the default control transfer\r
472 endpoint is capable of sending or receiving.\r
473 @param Request USB device request to send.\r
474 @param TransferDirection Specifies the data direction for the data stage.\r
475 @param Data Data buffer to be transmitted or received from USB device.\r
476 @param DataLength The size (in bytes) of the data buffer.\r
477 @param TimeOut Indicates the maximum timeout, in millisecond.\r
478 If Timeout is 0, then the caller must wait for the function\r
479 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
480 @param Translator Transaction translator to be used by this device.\r
481 @param TransferResult Return the result of this control transfer.\r
482\r
483 @retval EFI_SUCCESS Transfer was completed successfully.\r
484 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
485 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
486 @retval EFI_TIMEOUT Transfer failed due to timeout.\r
487 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
488\r
489**/\r
490EFI_STATUS\r
491EFIAPI\r
492XhcPeiControlTransfer (\r
493 IN EFI_PEI_SERVICES **PeiServices,\r
494 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
495 IN UINT8 DeviceAddress,\r
496 IN UINT8 DeviceSpeed,\r
497 IN UINTN MaximumPacketLength,\r
498 IN EFI_USB_DEVICE_REQUEST *Request,\r
499 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
500 IN OUT VOID *Data,\r
501 IN OUT UINTN *DataLength,\r
502 IN UINTN TimeOut,\r
503 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
504 OUT UINT32 *TransferResult\r
505 )\r
506{\r
507 PEI_XHC_DEV *Xhc;\r
508 URB *Urb;\r
509 UINT8 Endpoint;\r
510 UINT8 Index;\r
511 UINT8 DescriptorType;\r
512 UINT8 SlotId;\r
513 UINT8 TTT;\r
514 UINT8 MTT;\r
515 UINT32 MaxPacket0;\r
516 EFI_USB_HUB_DESCRIPTOR *HubDesc;\r
517 EFI_STATUS Status;\r
518 EFI_STATUS RecoveryStatus;\r
519 UINTN MapSize;\r
520 EFI_USB_PORT_STATUS PortStatus;\r
521 UINT32 State;\r
522 EFI_USB_DEVICE_REQUEST ClearPortRequest;\r
523 UINTN Len;\r
524\r
525 //\r
526 // Validate parameters\r
527 //\r
528 if ((Request == NULL) || (TransferResult == NULL)) {\r
529 return EFI_INVALID_PARAMETER;\r
530 }\r
531\r
532 if ((TransferDirection != EfiUsbDataIn) &&\r
533 (TransferDirection != EfiUsbDataOut) &&\r
534 (TransferDirection != EfiUsbNoData)) {\r
535 return EFI_INVALID_PARAMETER;\r
536 }\r
537\r
538 if ((TransferDirection == EfiUsbNoData) &&\r
539 ((Data != NULL) || (*DataLength != 0))) {\r
540 return EFI_INVALID_PARAMETER;\r
541 }\r
542\r
543 if ((TransferDirection != EfiUsbNoData) &&\r
544 ((Data == NULL) || (*DataLength == 0))) {\r
545 return EFI_INVALID_PARAMETER;\r
546 }\r
547\r
548 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
549 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&\r
550 (MaximumPacketLength != 512)\r
551 ) {\r
552 return EFI_INVALID_PARAMETER;\r
553 }\r
554\r
555 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
556 return EFI_INVALID_PARAMETER;\r
557 }\r
558\r
559 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {\r
560 return EFI_INVALID_PARAMETER;\r
561 }\r
562\r
563 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
564\r
565 Status = EFI_DEVICE_ERROR;\r
566 *TransferResult = EFI_USB_ERR_SYSTEM;\r
567 Len = 0;\r
568\r
569 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
570 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: HC is halted or has system error\n"));\r
571 goto ON_EXIT;\r
572 }\r
573\r
574 //\r
575 // Check if the device is still enabled before every transaction.\r
576 //\r
577 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
578 if (SlotId == 0) {\r
579 goto ON_EXIT;\r
580 }\r
581\r
582 //\r
583 // Hook the Set_Address request from UsbBus.\r
584 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.\r
585 //\r
586 if ((Request->Request == USB_REQ_SET_ADDRESS) &&\r
587 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
588 //\r
589 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.\r
590 // This way is used to clean the history to avoid using wrong device address afterwards.\r
591 //\r
592 for (Index = 0; Index < 255; Index++) {\r
593 if (!Xhc->UsbDevContext[Index + 1].Enabled &&\r
594 (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&\r
595 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8) Request->Value)) {\r
596 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;\r
597 }\r
598 }\r
599\r
600 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {\r
601 goto ON_EXIT;\r
602 }\r
603 //\r
604 // The actual device address has been assigned by XHCI during initializing the device slot.\r
605 // So we just need establish the mapping relationship between the device address requested from UsbBus\r
606 // and the actual device address assigned by XHCI. The following invocations through EFI_USB2_HC_PROTOCOL interface\r
607 // can find out the actual device address by it.\r
608 //\r
609 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8) Request->Value;\r
610 Status = EFI_SUCCESS;\r
611 goto ON_EXIT;\r
612 }\r
613\r
614 //\r
615 // Create a new URB, insert it into the asynchronous\r
616 // schedule list, then poll the execution status.\r
617 // Note that we encode the direction in address although default control\r
618 // endpoint is bidirectional. XhcPeiCreateUrb expects this\r
619 // combination of Ep addr and its direction.\r
620 //\r
621 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
622 Urb = XhcPeiCreateUrb (\r
623 Xhc,\r
624 DeviceAddress,\r
625 Endpoint,\r
626 DeviceSpeed,\r
627 MaximumPacketLength,\r
628 XHC_CTRL_TRANSFER,\r
629 Request,\r
630 Data,\r
631 *DataLength,\r
632 NULL,\r
633 NULL\r
634 );\r
635\r
636 if (Urb == NULL) {\r
637 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: failed to create URB"));\r
638 Status = EFI_OUT_OF_RESOURCES;\r
639 goto ON_EXIT;\r
640 }\r
641\r
642 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
643\r
644 //\r
645 // Get the status from URB. The result is updated in XhcPeiCheckUrbResult\r
646 // which is called by XhcPeiExecTransfer\r
647 //\r
648 *TransferResult = Urb->Result;\r
649 *DataLength = Urb->Completed;\r
650\r
12e6c738
FT
651 if (Status == EFI_TIMEOUT) {\r
652 //\r
653 // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
654 //\r
655 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);\r
656 if (EFI_ERROR(RecoveryStatus)) {\r
657 DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
d987459f 658 }\r
d987459f
SZ
659 goto FREE_URB;\r
660 } else {\r
12e6c738
FT
661 if (*TransferResult == EFI_USB_NOERROR) {\r
662 Status = EFI_SUCCESS;\r
663 } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
664 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
665 if (EFI_ERROR (RecoveryStatus)) {\r
666 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
667 }\r
668 Status = EFI_DEVICE_ERROR;\r
669 goto FREE_URB;\r
670 } else {\r
671 goto FREE_URB;\r
672 }\r
d987459f
SZ
673 }\r
674\r
675 //\r
676 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
677 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.\r
678 // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
679 //\r
680 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&\r
681 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||\r
682 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {\r
683 DescriptorType = (UINT8) (Request->Value >> 8);\r
684 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
685 ASSERT (Data != NULL);\r
686 //\r
687 // Store a copy of device scriptor as hub device need this info to configure endpoint.\r
688 //\r
689 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
690 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {\r
691 //\r
692 // If it's a usb3.0 device, then its max packet size is a 2^n.\r
693 //\r
694 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
695 } else {\r
696 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
697 }\r
698 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
699 if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {\r
700 Status = EFI_OUT_OF_RESOURCES;\r
701 goto FREE_URB;\r
702 }\r
703 if (Xhc->HcCParams.Data.Csz == 0) {\r
704 Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);\r
705 } else {\r
706 Status = XhcPeiEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r
707 }\r
708 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {\r
709 ASSERT (Data != NULL);\r
710 if (*DataLength == ((UINT16 *) Data)[1]) {\r
711 //\r
712 // Get configuration value from request, store the configuration descriptor for Configure_Endpoint cmd.\r
713 //\r
714 Index = (UINT8) Request->Value;\r
715 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
716 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);\r
717 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {\r
718 Status = EFI_OUT_OF_RESOURCES;\r
719 goto FREE_URB;\r
720 }\r
721 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
722 }\r
723 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
724 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {\r
725 ASSERT (Data != NULL);\r
726 HubDesc = (EFI_USB_HUB_DESCRIPTOR *) Data;\r
727 ASSERT (HubDesc->NumPorts <= 15);\r
728 //\r
729 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.\r
730 //\r
731 TTT = (UINT8) ((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);\r
732 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {\r
733 //\r
734 // Don't support multi-TT feature for super speed hub now.\r
735 //\r
736 MTT = 0;\r
737 DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));\r
738 } else {\r
739 MTT = 0;\r
740 }\r
741\r
742 if (Xhc->HcCParams.Data.Csz == 0) {\r
743 Status = XhcPeiConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
744 } else {\r
745 Status = XhcPeiConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
746 }\r
747 }\r
748 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
749 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {\r
750 //\r
751 // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
752 //\r
753 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
754 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {\r
755 if (Xhc->HcCParams.Data.Csz == 0) {\r
756 Status = XhcPeiSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
757 } else {\r
758 Status = XhcPeiSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
759 }\r
760 break;\r
761 }\r
762 }\r
763 } else if ((Request->Request == USB_REQ_GET_STATUS) &&\r
764 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {\r
765 ASSERT (Data != NULL);\r
766 //\r
767 // Hook Get_Status request from UsbBus to keep track of the port status change.\r
768 //\r
769 State = *(UINT32 *) Data;\r
770 PortStatus.PortStatus = 0;\r
771 PortStatus.PortChangeStatus = 0;\r
772\r
773 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
774 //\r
775 // For super speed hub, its bit10~12 presents the attached device speed.\r
776 //\r
777 if ((State & XHC_PORTSC_PS) >> 10 == 0) {\r
778 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
779 }\r
780 } else {\r
781 //\r
782 // For high or full/low speed hub, its bit9~10 presents the attached device speed.\r
783 //\r
784 if (XHC_BIT_IS_SET (State, BIT9)) {\r
785 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
786 } else if (XHC_BIT_IS_SET (State, BIT10)) {\r
787 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
788 }\r
789 }\r
790\r
791 //\r
792 // Convert the XHCI port/port change state to UEFI status\r
793 //\r
794 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
795 for (Index = 0; Index < MapSize; Index++) {\r
796 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {\r
797 PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);\r
798 }\r
799 }\r
800\r
801 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
802 for (Index = 0; Index < MapSize; Index++) {\r
803 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {\r
804 PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);\r
805 }\r
806 }\r
807\r
808 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
809\r
810 for (Index = 0; Index < MapSize; Index++) {\r
811 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {\r
812 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
813 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);\r
814 ClearPortRequest.Request = (UINT8) USB_REQ_CLEAR_FEATURE;\r
815 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;\r
816 ClearPortRequest.Index = Request->Index;\r
817 ClearPortRequest.Length = 0;\r
818\r
819 XhcPeiControlTransfer (\r
820 PeiServices,\r
821 This,\r
822 DeviceAddress,\r
823 DeviceSpeed,\r
824 MaximumPacketLength,\r
825 &ClearPortRequest,\r
826 EfiUsbNoData,\r
827 NULL,\r
828 &Len,\r
829 TimeOut,\r
830 Translator,\r
831 TransferResult\r
832 );\r
833 }\r
834 }\r
835\r
836 XhcPeiPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
837\r
838 *(UINT32 *) Data = *(UINT32 *) &PortStatus;\r
839 }\r
840\r
841FREE_URB:\r
842 XhcPeiFreeUrb (Xhc, Urb);\r
843\r
844ON_EXIT:\r
845\r
846 if (EFI_ERROR (Status)) {\r
847 DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
848 }\r
849\r
850 return Status;\r
851}\r
852\r
853/**\r
854 Submits bulk transfer to a bulk endpoint of a USB device.\r
855\r
856 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
857 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
858 @param DeviceAddress Target device address.\r
859 @param EndPointAddress Endpoint number and its direction in bit 7.\r
860 @param DeviceSpeed Device speed, Low speed device doesn't support\r
861 bulk transfer.\r
862 @param MaximumPacketLength Maximum packet size the endpoint is capable of\r
863 sending or receiving.\r
864 @param Data Array of pointers to the buffers of data to transmit\r
865 from or receive into.\r
866 @param DataLength The lenght of the data buffer.\r
867 @param DataToggle On input, the initial data toggle for the transfer;\r
868 On output, it is updated to to next data toggle to use of\r
869 the subsequent bulk transfer.\r
870 @param TimeOut Indicates the maximum time, in millisecond, which the\r
871 transfer is allowed to complete.\r
872 If Timeout is 0, then the caller must wait for the function\r
873 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.\r
874 @param Translator A pointr to the transaction translator data.\r
875 @param TransferResult A pointer to the detailed result information of the\r
876 bulk transfer.\r
877\r
878 @retval EFI_SUCCESS The transfer was completed successfully.\r
879 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
880 @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
881 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
882 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
883\r
884**/\r
885EFI_STATUS\r
886EFIAPI\r
887XhcPeiBulkTransfer (\r
888 IN EFI_PEI_SERVICES **PeiServices,\r
889 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
890 IN UINT8 DeviceAddress,\r
891 IN UINT8 EndPointAddress,\r
892 IN UINT8 DeviceSpeed,\r
893 IN UINTN MaximumPacketLength,\r
894 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
895 IN OUT UINTN *DataLength,\r
896 IN OUT UINT8 *DataToggle,\r
897 IN UINTN TimeOut,\r
898 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
899 OUT UINT32 *TransferResult\r
900 )\r
901{\r
902 PEI_XHC_DEV *Xhc;\r
903 URB *Urb;\r
904 UINT8 SlotId;\r
905 EFI_STATUS Status;\r
906 EFI_STATUS RecoveryStatus;\r
907\r
908 //\r
909 // Validate the parameters\r
910 //\r
911 if ((DataLength == NULL) || (*DataLength == 0) ||\r
912 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {\r
913 return EFI_INVALID_PARAMETER;\r
914 }\r
915\r
916 if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
917 return EFI_INVALID_PARAMETER;\r
918 }\r
919\r
920 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
921 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
922 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 512)) ||\r
923 ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength > 1024))) {\r
924 return EFI_INVALID_PARAMETER;\r
925 }\r
926\r
927 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
928\r
929 *TransferResult = EFI_USB_ERR_SYSTEM;\r
930 Status = EFI_DEVICE_ERROR;\r
931\r
932 if (XhcPeiIsHalt (Xhc) || XhcPeiIsSysError (Xhc)) {\r
933 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: HC is halted or has system error\n"));\r
934 goto ON_EXIT;\r
935 }\r
936\r
937 //\r
938 // Check if the device is still enabled before every transaction.\r
939 //\r
940 SlotId = XhcPeiBusDevAddrToSlotId (Xhc, DeviceAddress);\r
941 if (SlotId == 0) {\r
942 goto ON_EXIT;\r
943 }\r
944\r
945 //\r
946 // Create a new URB, insert it into the asynchronous\r
947 // schedule list, then poll the execution status.\r
948 //\r
949 Urb = XhcPeiCreateUrb (\r
950 Xhc,\r
951 DeviceAddress,\r
952 EndPointAddress,\r
953 DeviceSpeed,\r
954 MaximumPacketLength,\r
955 XHC_BULK_TRANSFER,\r
956 NULL,\r
957 Data[0],\r
958 *DataLength,\r
959 NULL,\r
960 NULL\r
961 );\r
962\r
963 if (Urb == NULL) {\r
964 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: failed to create URB\n"));\r
965 Status = EFI_OUT_OF_RESOURCES;\r
966 goto ON_EXIT;\r
967 }\r
968\r
969 Status = XhcPeiExecTransfer (Xhc, FALSE, Urb, TimeOut);\r
970\r
971 *TransferResult = Urb->Result;\r
972 *DataLength = Urb->Completed;\r
973\r
12e6c738
FT
974 if (Status == EFI_TIMEOUT) {\r
975 //\r
976 // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
977 //\r
978 RecoveryStatus = XhcPeiDequeueTrbFromEndpoint(Xhc, Urb);\r
979 if (EFI_ERROR(RecoveryStatus)) {\r
980 DEBUG((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
981 }\r
982 } else {\r
983 if (*TransferResult == EFI_USB_NOERROR) {\r
984 Status = EFI_SUCCESS;\r
985 } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
986 RecoveryStatus = XhcPeiRecoverHaltedEndpoint(Xhc, Urb);\r
987 if (EFI_ERROR (RecoveryStatus)) {\r
988 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
989 }\r
990 Status = EFI_DEVICE_ERROR;\r
d987459f 991 }\r
d987459f
SZ
992 }\r
993\r
994 XhcPeiFreeUrb (Xhc, Urb);\r
995\r
996ON_EXIT:\r
997\r
998 if (EFI_ERROR (Status)) {\r
999 DEBUG ((EFI_D_ERROR, "XhcPeiBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
1000 }\r
1001\r
1002 return Status;\r
1003}\r
1004\r
1005/**\r
1006 Retrieves the number of root hub ports.\r
1007\r
1008 @param[in] PeiServices The pointer to the PEI Services Table.\r
1009 @param[in] This The pointer to this instance of the\r
1010 PEI_USB2_HOST_CONTROLLER_PPI.\r
1011 @param[out] PortNumber The pointer to the number of the root hub ports.\r
1012\r
1013 @retval EFI_SUCCESS The port number was retrieved successfully.\r
1014 @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
1015\r
1016**/\r
1017EFI_STATUS\r
1018EFIAPI\r
1019XhcPeiGetRootHubPortNumber (\r
1020 IN EFI_PEI_SERVICES **PeiServices,\r
1021 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1022 OUT UINT8 *PortNumber\r
1023 )\r
1024{\r
1025 PEI_XHC_DEV *XhcDev;\r
1026 XhcDev = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1027\r
1028 if (PortNumber == NULL) {\r
1029 return EFI_INVALID_PARAMETER;\r
1030 }\r
1031\r
1032 *PortNumber = XhcDev->HcSParams1.Data.MaxPorts;\r
1033 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortNumber: PortNumber = %x\n", *PortNumber));\r
1034 return EFI_SUCCESS;\r
1035}\r
1036\r
1037/**\r
1038 Clears a feature for the specified root hub port.\r
1039\r
1040 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
1041 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
1042 @param PortNumber Specifies the root hub port whose feature\r
1043 is requested to be cleared.\r
1044 @param PortFeature Indicates the feature selector associated with the\r
1045 feature clear request.\r
1046\r
1047 @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
1048 for the USB root hub port specified by PortNumber.\r
1049 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1050\r
1051**/\r
1052EFI_STATUS\r
1053EFIAPI\r
1054XhcPeiClearRootHubPortFeature (\r
1055 IN EFI_PEI_SERVICES **PeiServices,\r
1056 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1057 IN UINT8 PortNumber,\r
1058 IN EFI_USB_PORT_FEATURE PortFeature\r
1059 )\r
1060{\r
1061 PEI_XHC_DEV *Xhc;\r
1062 UINT32 Offset;\r
1063 UINT32 State;\r
1064 EFI_STATUS Status;\r
1065\r
1066 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1067 Status = EFI_SUCCESS;\r
1068\r
1069 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
1070 Status = EFI_INVALID_PARAMETER;\r
1071 goto ON_EXIT;\r
1072 }\r
1073\r
1074 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
1075 State = XhcPeiReadOpReg (Xhc, Offset);\r
1076 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
1077\r
1078 //\r
1079 // Mask off the port status change bits, these bits are\r
1080 // write clean bits\r
1081 //\r
1082 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
1083\r
1084 switch (PortFeature) {\r
1085 case EfiUsbPortEnable:\r
1086 //\r
1087 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
1088 // A port may be disabled by software writing a '1' to this flag.\r
1089 //\r
1090 State |= XHC_PORTSC_PED;\r
1091 State &= ~XHC_PORTSC_RESET;\r
1092 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1093 break;\r
1094\r
1095 case EfiUsbPortSuspend:\r
1096 State |= XHC_PORTSC_LWS;\r
1097 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1098 State &= ~XHC_PORTSC_PLS;\r
1099 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1100 break;\r
1101\r
1102 case EfiUsbPortReset:\r
1103 //\r
1104 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:\r
1105 // Register bits indicate status when read, a clear bit may be set by\r
1106 // writing a '1'. Writing a '0' to RW1S bits has no effect.\r
1107 //\r
1108 break;\r
1109\r
1110 case EfiUsbPortPower:\r
1111 if (Xhc->HcCParams.Data.Ppc) {\r
1112 //\r
1113 // Port Power Control supported\r
1114 //\r
1115 State &= ~XHC_PORTSC_PP;\r
1116 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1117 }\r
1118 break;\r
1119\r
1120 case EfiUsbPortOwner:\r
1121 //\r
1122 // XHCI root hub port don't has the owner bit, ignore the operation\r
1123 //\r
1124 break;\r
1125\r
1126 case EfiUsbPortConnectChange:\r
1127 //\r
1128 // Clear connect status change\r
1129 //\r
1130 State |= XHC_PORTSC_CSC;\r
1131 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1132 break;\r
1133\r
1134 case EfiUsbPortEnableChange:\r
1135 //\r
1136 // Clear enable status change\r
1137 //\r
1138 State |= XHC_PORTSC_PEC;\r
1139 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1140 break;\r
1141\r
1142 case EfiUsbPortOverCurrentChange:\r
1143 //\r
1144 // Clear PortOverCurrent change\r
1145 //\r
1146 State |= XHC_PORTSC_OCC;\r
1147 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1148 break;\r
1149\r
1150 case EfiUsbPortResetChange:\r
1151 //\r
1152 // Clear Port Reset change\r
1153 //\r
1154 State |= XHC_PORTSC_PRC;\r
1155 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1156 break;\r
1157\r
1158 case EfiUsbPortSuspendChange:\r
1159 //\r
1160 // Not supported or not related operation\r
1161 //\r
1162 break;\r
1163\r
1164 default:\r
1165 Status = EFI_INVALID_PARAMETER;\r
1166 break;\r
1167 }\r
1168\r
1169ON_EXIT:\r
1170 DEBUG ((EFI_D_INFO, "XhcPeiClearRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
1171 return Status;\r
1172}\r
1173\r
1174/**\r
1175 Sets a feature for the specified root hub port.\r
1176\r
1177 @param PeiServices The pointer of EFI_PEI_SERVICES\r
1178 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI\r
1179 @param PortNumber Root hub port to set.\r
1180 @param PortFeature Feature to set.\r
1181\r
1182 @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
1183 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
1184 @retval EFI_TIMEOUT The time out occurred.\r
1185\r
1186**/\r
1187EFI_STATUS\r
1188EFIAPI\r
1189XhcPeiSetRootHubPortFeature (\r
1190 IN EFI_PEI_SERVICES **PeiServices,\r
1191 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1192 IN UINT8 PortNumber,\r
1193 IN EFI_USB_PORT_FEATURE PortFeature\r
1194 )\r
1195{\r
1196 PEI_XHC_DEV *Xhc;\r
1197 UINT32 Offset;\r
1198 UINT32 State;\r
1199 EFI_STATUS Status;\r
1200\r
1201 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1202 Status = EFI_SUCCESS;\r
1203\r
1204 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
1205 Status = EFI_INVALID_PARAMETER;\r
1206 goto ON_EXIT;\r
1207 }\r
1208\r
1209 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
1210 State = XhcPeiReadOpReg (Xhc, Offset);\r
1211 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: Port: %x State: %x\n", PortNumber, State));\r
1212\r
1213 //\r
1214 // Mask off the port status change bits, these bits are\r
1215 // write clean bits\r
1216 //\r
1217 State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
1218\r
1219 switch (PortFeature) {\r
1220 case EfiUsbPortEnable:\r
1221 //\r
1222 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
1223 // A port may be disabled by software writing a '1' to this flag.\r
1224 //\r
1225 break;\r
1226\r
1227 case EfiUsbPortSuspend:\r
1228 State |= XHC_PORTSC_LWS;\r
1229 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1230 State &= ~XHC_PORTSC_PLS;\r
1231 State |= (3 << 5) ;\r
1232 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1233 break;\r
1234\r
1235 case EfiUsbPortReset:\r
1236 //\r
1237 // Make sure Host Controller not halt before reset it\r
1238 //\r
1239 if (XhcPeiIsHalt (Xhc)) {\r
1240 Status = XhcPeiRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
1241 if (EFI_ERROR (Status)) {\r
1242 break;\r
1243 }\r
1244 }\r
1245\r
1246 //\r
1247 // 4.3.1 Resetting a Root Hub Port\r
1248 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
1249 // 2) Wait for a successful Port Status Change Event for the port, where the Port Reset Change (PRC)\r
1250 // bit in the PORTSC field is set to '1'.\r
1251 //\r
1252 State |= XHC_PORTSC_RESET;\r
1253 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1254 XhcPeiWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
1255 break;\r
1256\r
1257 case EfiUsbPortPower:\r
1258 if (Xhc->HcCParams.Data.Ppc) {\r
1259 //\r
1260 // Port Power Control supported\r
1261 //\r
1262 State |= XHC_PORTSC_PP;\r
1263 XhcPeiWriteOpReg (Xhc, Offset, State);\r
1264 }\r
1265 break;\r
1266\r
1267 case EfiUsbPortOwner:\r
1268 //\r
1269 // XHCI root hub port don't has the owner bit, ignore the operation\r
1270 //\r
1271 break;\r
1272\r
1273 default:\r
1274 Status = EFI_INVALID_PARAMETER;\r
1275 }\r
1276\r
1277ON_EXIT:\r
1278 DEBUG ((EFI_D_INFO, "XhcPeiSetRootHubPortFeature: PortFeature: %x Status = %r\n", PortFeature, Status));\r
1279 return Status;\r
1280}\r
1281\r
1282/**\r
1283 Retrieves the current status of a USB root hub port.\r
1284\r
1285 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
1286 @param This The pointer of PEI_USB2_HOST_CONTROLLER_PPI.\r
1287 @param PortNumber The root hub port to retrieve the state from.\r
1288 @param PortStatus Variable to receive the port state.\r
1289\r
1290 @retval EFI_SUCCESS The status of the USB root hub port specified.\r
1291 by PortNumber was returned in PortStatus.\r
1292 @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
1293\r
1294**/\r
1295EFI_STATUS\r
1296EFIAPI\r
1297XhcPeiGetRootHubPortStatus (\r
1298 IN EFI_PEI_SERVICES **PeiServices,\r
1299 IN PEI_USB2_HOST_CONTROLLER_PPI *This,\r
1300 IN UINT8 PortNumber,\r
1301 OUT EFI_USB_PORT_STATUS *PortStatus\r
1302 )\r
1303{\r
1304 PEI_XHC_DEV *Xhc;\r
1305 UINT32 Offset;\r
1306 UINT32 State;\r
1307 UINTN Index;\r
1308 UINTN MapSize;\r
1309 USB_DEV_ROUTE ParentRouteChart;\r
1310\r
1311 if (PortStatus == NULL) {\r
1312 return EFI_INVALID_PARAMETER;\r
1313 }\r
1314\r
1315 Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS (This);\r
1316\r
1317 if (PortNumber >= Xhc->HcSParams1.Data.MaxPorts) {\r
1318 return EFI_INVALID_PARAMETER;\r
1319 }\r
1320\r
1321 //\r
1322 // Clear port status.\r
1323 //\r
1324 PortStatus->PortStatus = 0;\r
1325 PortStatus->PortChangeStatus = 0;\r
1326\r
1327 Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
1328 State = XhcPeiReadOpReg (Xhc, Offset);\r
1329 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: Port: %x State: %x\n", PortNumber, State));\r
1330\r
1331 //\r
1332 // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.\r
1333 //\r
1334 switch ((State & XHC_PORTSC_PS) >> 10) {\r
1335 case 2:\r
1336 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
1337 break;\r
1338\r
1339 case 3:\r
1340 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
1341 break;\r
1342\r
1343 case 4:\r
1344 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
1345 break;\r
1346\r
1347 default:\r
1348 break;\r
1349 }\r
1350\r
1351 //\r
1352 // Convert the XHCI port/port change state to UEFI status\r
1353 //\r
1354 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
1355\r
1356 for (Index = 0; Index < MapSize; Index++) {\r
1357 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
1358 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
1359 }\r
1360 }\r
1361 //\r
1362 // Bit5~8 reflects its current link state.\r
1363 //\r
1364 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {\r
1365 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
1366 }\r
1367\r
1368 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
1369\r
1370 for (Index = 0; Index < MapSize; Index++) {\r
1371 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
1372 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
1373 }\r
1374 }\r
1375\r
1376 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
1377\r
1378 for (Index = 0; Index < MapSize; Index++) {\r
1379 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {\r
1380 XhcPeiClearRootHubPortFeature (PeiServices, This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);\r
1381 }\r
1382 }\r
1383\r
1384 //\r
1385 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
1386 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
1387 //\r
1388 ParentRouteChart.Dword = 0;\r
1389 XhcPeiPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);\r
1390\r
1391 DEBUG ((EFI_D_INFO, "XhcPeiGetRootHubPortStatus: PortChangeStatus: %x PortStatus: %x\n", PortStatus->PortChangeStatus, PortStatus->PortStatus));\r
1392 return EFI_SUCCESS;\r
1393}\r
1394\r
1395/**\r
1396 @param FileHandle Handle of the file being invoked.\r
1397 @param PeiServices Describes the list of possible PEI Services.\r
1398\r
1399 @retval EFI_SUCCESS PPI successfully installed.\r
1400\r
1401**/\r
1402EFI_STATUS\r
1403EFIAPI\r
1404XhcPeimEntry (\r
1405 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1406 IN CONST EFI_PEI_SERVICES **PeiServices\r
1407 )\r
1408{\r
1409 PEI_USB_CONTROLLER_PPI *UsbControllerPpi;\r
1410 EFI_STATUS Status;\r
1411 UINT8 Index;\r
1412 UINTN ControllerType;\r
1413 UINTN BaseAddress;\r
1414 UINTN MemPages;\r
1415 PEI_XHC_DEV *XhcDev;\r
1416 EFI_PHYSICAL_ADDRESS TempPtr;\r
1417 UINT32 PageSize;\r
1418\r
1419 //\r
1420 // Shadow this PEIM to run from memory.\r
1421 //\r
1422 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
1423 return EFI_SUCCESS;\r
1424 }\r
1425\r
1426 Status = PeiServicesLocatePpi (\r
1427 &gPeiUsbControllerPpiGuid,\r
1428 0,\r
1429 NULL,\r
1430 (VOID **) &UsbControllerPpi\r
1431 );\r
1432 if (EFI_ERROR (Status)) {\r
1433 return EFI_UNSUPPORTED;\r
1434 }\r
1435\r
1436 Index = 0;\r
1437 while (TRUE) {\r
1438 Status = UsbControllerPpi->GetUsbController (\r
1439 (EFI_PEI_SERVICES **) PeiServices,\r
1440 UsbControllerPpi,\r
1441 Index,\r
1442 &ControllerType,\r
1443 &BaseAddress\r
1444 );\r
1445 //\r
1446 // When status is error, it means no controller is found.\r
1447 //\r
1448 if (EFI_ERROR (Status)) {\r
1449 break;\r
1450 }\r
1451\r
1452 //\r
1453 // This PEIM is for XHC type controller.\r
1454 //\r
1455 if (ControllerType != PEI_XHCI_CONTROLLER) {\r
1456 Index++;\r
1457 continue;\r
1458 }\r
1459\r
1460 MemPages = EFI_SIZE_TO_PAGES (sizeof (PEI_XHC_DEV));\r
1461 Status = PeiServicesAllocatePages (\r
1462 EfiBootServicesData,\r
1463 MemPages,\r
1464 &TempPtr\r
1465 );\r
1466 if (EFI_ERROR (Status)) {\r
1467 return EFI_OUT_OF_RESOURCES;\r
1468 }\r
1469 ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (MemPages));\r
1470 XhcDev = (PEI_XHC_DEV *) ((UINTN) TempPtr);\r
1471\r
1472 XhcDev->Signature = USB_XHC_DEV_SIGNATURE;\r
1473 XhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
4918a06a 1474 XhcDev->CapLength = (UINT8) (XhcPeiReadCapRegister (XhcDev, XHC_CAPLENGTH_OFFSET) & 0x0FF);\r
d987459f
SZ
1475 XhcDev->HcSParams1.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS1_OFFSET);\r
1476 XhcDev->HcSParams2.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCSPARAMS2_OFFSET);\r
1477 XhcDev->HcCParams.Dword = XhcPeiReadCapRegister (XhcDev, XHC_HCCPARAMS_OFFSET);\r
1478 XhcDev->DBOff = XhcPeiReadCapRegister (XhcDev, XHC_DBOFF_OFFSET);\r
1479 XhcDev->RTSOff = XhcPeiReadCapRegister (XhcDev, XHC_RTSOFF_OFFSET);\r
1480\r
1481 //\r
1482 // This PageSize field defines the page size supported by the xHC implementation.\r
1483 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
1484 // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
1485 //\r
1486 PageSize = XhcPeiReadOpReg (XhcDev, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;\r
1487 XhcDev->PageSize = 1 << (HighBitSet32 (PageSize) + 12);\r
1488\r
1489 DEBUG ((EFI_D_INFO, "XhciPei: UsbHostControllerBaseAddress: %x\n", XhcDev->UsbHostControllerBaseAddress));\r
1490 DEBUG ((EFI_D_INFO, "XhciPei: CapLength: %x\n", XhcDev->CapLength));\r
1491 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams1: %x\n", XhcDev->HcSParams1.Dword));\r
1492 DEBUG ((EFI_D_INFO, "XhciPei: HcSParams2: %x\n", XhcDev->HcSParams2.Dword));\r
1493 DEBUG ((EFI_D_INFO, "XhciPei: HcCParams: %x\n", XhcDev->HcCParams.Dword));\r
1494 DEBUG ((EFI_D_INFO, "XhciPei: DBOff: %x\n", XhcDev->DBOff));\r
1495 DEBUG ((EFI_D_INFO, "XhciPei: RTSOff: %x\n", XhcDev->RTSOff));\r
1496 DEBUG ((EFI_D_INFO, "XhciPei: PageSize: %x\n", XhcDev->PageSize));\r
1497\r
1498 XhcPeiResetHC (XhcDev, XHC_RESET_TIMEOUT);\r
1499 ASSERT (XhcPeiIsHalt (XhcDev));\r
1500\r
1501 //\r
1502 // Initialize the schedule\r
1503 //\r
1504 XhcPeiInitSched (XhcDev);\r
1505\r
1506 //\r
1507 // Start the Host Controller\r
1508 //\r
1509 XhcPeiRunHC (XhcDev, XHC_GENERIC_TIMEOUT);\r
1510\r
1511 //\r
1512 // Wait for root port state stable\r
1513 //\r
1514 MicroSecondDelay (XHC_ROOT_PORT_STATE_STABLE);\r
1515\r
1516 XhcDev->Usb2HostControllerPpi.ControlTransfer = XhcPeiControlTransfer;\r
1517 XhcDev->Usb2HostControllerPpi.BulkTransfer = XhcPeiBulkTransfer;\r
1518 XhcDev->Usb2HostControllerPpi.GetRootHubPortNumber = XhcPeiGetRootHubPortNumber;\r
1519 XhcDev->Usb2HostControllerPpi.GetRootHubPortStatus = XhcPeiGetRootHubPortStatus;\r
1520 XhcDev->Usb2HostControllerPpi.SetRootHubPortFeature = XhcPeiSetRootHubPortFeature;\r
1521 XhcDev->Usb2HostControllerPpi.ClearRootHubPortFeature = XhcPeiClearRootHubPortFeature;\r
1522\r
1523 XhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
1524 XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
1525 XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;\r
1526\r
1527 PeiServicesInstallPpi (&XhcDev->PpiDescriptor);\r
1528\r
1529 Index++;\r
1530 }\r
1531\r
1532 return EFI_SUCCESS;\r
1533}\r
1534\r