MdeModulePkg/UsbBusPei: Improve PEI USB enumeration

Unlike DXE USB enumeration that enumerates all changed ports on timer
interrupt, PEI USB Enumeration runs once at the driver entry point.
USB3.x devices initially appear in USB2.0 ports. When the USB2.0 port is
reset, the USB3.x device disappears from the USB2.0 port and appears on the
USB3.0 port. The USB3.x device won't be enumerated if the USB2.0 port
number is greater than the USB3.0 port number. Re-enumerate USB to make
sure USB3.x devices in this case.

Signed-off-by: Phil Noh <Phil.Noh@amd.com>
This commit is contained in:
Phil Noh 2025-02-10 18:51:35 -06:00 committed by Liming Gao
parent bc664d1830
commit 0192f2d7cb
1 changed files with 172 additions and 163 deletions

View File

@ -1,6 +1,7 @@
/** @file /** @file
The module to produce Usb Bus PPI. The module to produce Usb Bus PPI.
Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.<BR>
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent SPDX-License-Identifier: BSD-2-Clause-Patent
@ -428,6 +429,7 @@ PeiUsbEnumeration (
UINT8 CurrentAddress; UINT8 CurrentAddress;
UINTN InterfaceIndex; UINTN InterfaceIndex;
UINTN EndpointIndex; UINTN EndpointIndex;
UINT8 UsbEnumLoop;
CurrentAddress = 0; CurrentAddress = 0;
if (Usb2HcPpi != NULL) { if (Usb2HcPpi != NULL) {
@ -449,161 +451,40 @@ PeiUsbEnumeration (
DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort)); DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));
for (Index = 0; Index < NumOfRootPort; Index++) { //
// // USB3.x devices initially appear in USB2.0 ports. When the USB2.0 port is reset, the USB3.x device disappears
// First get root port status to detect changes happen // from the USB2.0 port and appears on the USB3.0 port. The USB3.x device won't be enumerated if the USB2.0 port
// // number is greater than the USB3.0 port number. Re-enumerate USB to make sure USB3.x devices in this case.
if (Usb2HcPpi != NULL) { //
Usb2HcPpi->GetRootHubPortStatus ( for (UsbEnumLoop = 0; UsbEnumLoop < 2; UsbEnumLoop++) {
PeiServices, for (Index = 0; Index < NumOfRootPort; Index++) {
Usb2HcPpi, //
(UINT8)Index, // First get root port status to detect changes happen
&PortStatus //
); if (Usb2HcPpi != NULL) {
} else { Usb2HcPpi->GetRootHubPortStatus (
UsbHcPpi->GetRootHubPortStatus ( PeiServices,
PeiServices, Usb2HcPpi,
UsbHcPpi, (UINT8)Index,
(UINT8)Index, &PortStatus
&PortStatus
);
}
DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
//
// Only handle connection/enable/overcurrent/reset change.
//
if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
continue;
} else {
if (IsPortConnect (PortStatus.PortStatus)) {
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
MemPages,
&AllocateAddress
); );
if (EFI_ERROR (Status)) { } else {
return EFI_OUT_OF_RESOURCES; UsbHcPpi->GetRootHubPortStatus (
} PeiServices,
UsbHcPpi,
(UINT8)Index,
&PortStatus
);
}
PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress); DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE)); //
// Only handle connection/enable/overcurrent/reset change.
PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE; //
PeiUsbDevice->DeviceAddress = 0; if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
PeiUsbDevice->MaxPacketSize0 = 8; continue;
PeiUsbDevice->DataToggle = 0; } else {
CopyMem ( if (IsPortConnect (PortStatus.PortStatus)) {
&(PeiUsbDevice->UsbIoPpi),
&mUsbIoPpi,
sizeof (PEI_USB_IO_PPI)
);
CopyMem (
&(PeiUsbDevice->UsbIoPpiList),
&mUsbIoPpiList,
sizeof (EFI_PEI_PPI_DESCRIPTOR)
);
PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
PeiUsbDevice->UsbHcPpi = UsbHcPpi;
PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
PeiUsbDevice->IsHub = 0x0;
PeiUsbDevice->DownStreamPortNo = 0x0;
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))
{
//
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
//
ResetRootPort (
PeiServices,
PeiUsbDevice->UsbHcPpi,
PeiUsbDevice->Usb2HcPpi,
Index,
0
);
if (Usb2HcPpi != NULL) {
Usb2HcPpi->GetRootHubPortStatus (
PeiServices,
Usb2HcPpi,
(UINT8)Index,
&PortStatus
);
} else {
UsbHcPpi->GetRootHubPortStatus (
PeiServices,
UsbHcPpi,
(UINT8)Index,
&PortStatus
);
}
} else {
if (Usb2HcPpi != NULL) {
Usb2HcPpi->ClearRootHubPortFeature (
PeiServices,
Usb2HcPpi,
(UINT8)Index,
EfiUsbPortResetChange
);
} else {
UsbHcPpi->ClearRootHubPortFeature (
PeiServices,
UsbHcPpi,
(UINT8)Index,
EfiUsbPortResetChange
);
}
}
PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 512;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 64;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 8;
} else {
PeiUsbDevice->MaxPacketSize0 = 8;
}
//
// Configure that Usb Device
//
Status = PeiConfigureUsbDevice (
PeiServices,
PeiUsbDevice,
Index,
&CurrentAddress
);
if (EFI_ERROR (Status)) {
continue;
}
DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
PeiUsbDevice->IsHub = 0x1;
Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
if (EFI_ERROR (Status)) {
return Status;
}
PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
}
for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
//
// Begin to deal with the new device
//
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1; MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
Status = PeiServicesAllocatePages ( Status = PeiServicesAllocatePages (
EfiBootServicesCode, EfiBootServicesCode,
@ -614,15 +495,106 @@ PeiUsbEnumeration (
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE)); PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress); ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));
PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
PeiUsbDevice->DeviceAddress = 0;
PeiUsbDevice->MaxPacketSize0 = 8;
PeiUsbDevice->DataToggle = 0;
CopyMem (
&(PeiUsbDevice->UsbIoPpi),
&mUsbIoPpi,
sizeof (PEI_USB_IO_PPI)
);
CopyMem (
&(PeiUsbDevice->UsbIoPpiList),
&mUsbIoPpiList,
sizeof (EFI_PEI_PPI_DESCRIPTOR)
);
PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi; PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex]; PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) { PeiUsbDevice->UsbHcPpi = UsbHcPpi;
PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex]; PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
PeiUsbDevice->IsHub = 0x0;
PeiUsbDevice->DownStreamPortNo = 0x0;
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))
{
//
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
//
ResetRootPort (
PeiServices,
PeiUsbDevice->UsbHcPpi,
PeiUsbDevice->Usb2HcPpi,
Index,
0
);
if (Usb2HcPpi != NULL) {
Usb2HcPpi->GetRootHubPortStatus (
PeiServices,
Usb2HcPpi,
(UINT8)Index,
&PortStatus
);
} else {
UsbHcPpi->GetRootHubPortStatus (
PeiServices,
UsbHcPpi,
(UINT8)Index,
&PortStatus
);
}
} else {
if (Usb2HcPpi != NULL) {
Usb2HcPpi->ClearRootHubPortFeature (
PeiServices,
Usb2HcPpi,
(UINT8)Index,
EfiUsbPortResetChange
);
} else {
UsbHcPpi->ClearRootHubPortFeature (
PeiServices,
UsbHcPpi,
(UINT8)Index,
EfiUsbPortResetChange
);
}
} }
PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 512;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 64;
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
PeiUsbDevice->MaxPacketSize0 = 8;
} else {
PeiUsbDevice->MaxPacketSize0 = 8;
}
//
// Configure that Usb Device
//
Status = PeiConfigureUsbDevice (
PeiServices,
PeiUsbDevice,
Index,
&CurrentAddress
);
if (EFI_ERROR (Status)) {
continue;
}
DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList); Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) { if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
@ -635,11 +607,48 @@ PeiUsbEnumeration (
PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress); PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
} }
for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
//
// Begin to deal with the new device
//
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
MemPages,
&AllocateAddress
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE));
PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex];
for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
}
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
PeiUsbDevice->IsHub = 0x1;
Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
if (EFI_ERROR (Status)) {
return Status;
}
PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
}
}
} else {
//
// Disconnect change happen, currently we don't support
//
} }
} else {
//
// Disconnect change happen, currently we don't support
//
} }
} }
} }