Skip to content

Commit 0192f2d

Browse files
Phil Nohlgao4
authored andcommitted
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>
1 parent bc664d1 commit 0192f2d

1 file changed

Lines changed: 170 additions & 161 deletions

File tree

MdeModulePkg/Bus/Usb/UsbBusPei/UsbPeim.c

Lines changed: 170 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @file
22
The module to produce Usb Bus PPI.
33
4+
Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.<BR>
45
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
56
67
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -428,6 +429,7 @@ PeiUsbEnumeration (
428429
UINT8 CurrentAddress;
429430
UINTN InterfaceIndex;
430431
UINTN EndpointIndex;
432+
UINT8 UsbEnumLoop;
431433

432434
CurrentAddress = 0;
433435
if (Usb2HcPpi != NULL) {
@@ -449,179 +451,149 @@ PeiUsbEnumeration (
449451

450452
DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: NumOfRootPort: %x\n", NumOfRootPort));
451453

452-
for (Index = 0; Index < NumOfRootPort; Index++) {
453-
//
454-
// First get root port status to detect changes happen
455-
//
456-
if (Usb2HcPpi != NULL) {
457-
Usb2HcPpi->GetRootHubPortStatus (
458-
PeiServices,
459-
Usb2HcPpi,
460-
(UINT8)Index,
461-
&PortStatus
462-
);
463-
} else {
464-
UsbHcPpi->GetRootHubPortStatus (
465-
PeiServices,
466-
UsbHcPpi,
467-
(UINT8)Index,
468-
&PortStatus
469-
);
470-
}
471-
472-
DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
473-
//
474-
// Only handle connection/enable/overcurrent/reset change.
475-
//
476-
if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
477-
continue;
478-
} else {
479-
if (IsPortConnect (PortStatus.PortStatus)) {
480-
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
481-
Status = PeiServicesAllocatePages (
482-
EfiBootServicesCode,
483-
MemPages,
484-
&AllocateAddress
454+
//
455+
// USB3.x devices initially appear in USB2.0 ports. When the USB2.0 port is reset, the USB3.x device disappears
456+
// 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
457+
// number is greater than the USB3.0 port number. Re-enumerate USB to make sure USB3.x devices in this case.
458+
//
459+
for (UsbEnumLoop = 0; UsbEnumLoop < 2; UsbEnumLoop++) {
460+
for (Index = 0; Index < NumOfRootPort; Index++) {
461+
//
462+
// First get root port status to detect changes happen
463+
//
464+
if (Usb2HcPpi != NULL) {
465+
Usb2HcPpi->GetRootHubPortStatus (
466+
PeiServices,
467+
Usb2HcPpi,
468+
(UINT8)Index,
469+
&PortStatus
485470
);
486-
if (EFI_ERROR (Status)) {
487-
return EFI_OUT_OF_RESOURCES;
488-
}
471+
} else {
472+
UsbHcPpi->GetRootHubPortStatus (
473+
PeiServices,
474+
UsbHcPpi,
475+
(UINT8)Index,
476+
&PortStatus
477+
);
478+
}
489479

490-
PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
491-
ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));
480+
DEBUG ((DEBUG_INFO, "USB Status --- Port: %x ConnectChange[%04x] Status[%04x]\n", Index, PortStatus.PortChangeStatus, PortStatus.PortStatus));
481+
//
482+
// Only handle connection/enable/overcurrent/reset change.
483+
//
484+
if ((PortStatus.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
485+
continue;
486+
} else {
487+
if (IsPortConnect (PortStatus.PortStatus)) {
488+
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
489+
Status = PeiServicesAllocatePages (
490+
EfiBootServicesCode,
491+
MemPages,
492+
&AllocateAddress
493+
);
494+
if (EFI_ERROR (Status)) {
495+
return EFI_OUT_OF_RESOURCES;
496+
}
492497

493-
PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
494-
PeiUsbDevice->DeviceAddress = 0;
495-
PeiUsbDevice->MaxPacketSize0 = 8;
496-
PeiUsbDevice->DataToggle = 0;
497-
CopyMem (
498-
&(PeiUsbDevice->UsbIoPpi),
499-
&mUsbIoPpi,
500-
sizeof (PEI_USB_IO_PPI)
501-
);
502-
CopyMem (
503-
&(PeiUsbDevice->UsbIoPpiList),
504-
&mUsbIoPpiList,
505-
sizeof (EFI_PEI_PPI_DESCRIPTOR)
506-
);
507-
PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
508-
PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
509-
PeiUsbDevice->UsbHcPpi = UsbHcPpi;
510-
PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
511-
PeiUsbDevice->IsHub = 0x0;
512-
PeiUsbDevice->DownStreamPortNo = 0x0;
498+
PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
499+
ZeroMem (PeiUsbDevice, sizeof (PEI_USB_DEVICE));
513500

514-
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
515-
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))
516-
{
517-
//
518-
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
519-
//
520-
ResetRootPort (
521-
PeiServices,
522-
PeiUsbDevice->UsbHcPpi,
523-
PeiUsbDevice->Usb2HcPpi,
524-
Index,
525-
0
501+
PeiUsbDevice->Signature = PEI_USB_DEVICE_SIGNATURE;
502+
PeiUsbDevice->DeviceAddress = 0;
503+
PeiUsbDevice->MaxPacketSize0 = 8;
504+
PeiUsbDevice->DataToggle = 0;
505+
CopyMem (
506+
&(PeiUsbDevice->UsbIoPpi),
507+
&mUsbIoPpi,
508+
sizeof (PEI_USB_IO_PPI)
526509
);
527-
528-
if (Usb2HcPpi != NULL) {
529-
Usb2HcPpi->GetRootHubPortStatus (
530-
PeiServices,
531-
Usb2HcPpi,
532-
(UINT8)Index,
533-
&PortStatus
534-
);
535-
} else {
536-
UsbHcPpi->GetRootHubPortStatus (
537-
PeiServices,
538-
UsbHcPpi,
539-
(UINT8)Index,
540-
&PortStatus
541-
);
542-
}
543-
} else {
544-
if (Usb2HcPpi != NULL) {
545-
Usb2HcPpi->ClearRootHubPortFeature (
546-
PeiServices,
547-
Usb2HcPpi,
548-
(UINT8)Index,
549-
EfiUsbPortResetChange
550-
);
510+
CopyMem (
511+
&(PeiUsbDevice->UsbIoPpiList),
512+
&mUsbIoPpiList,
513+
sizeof (EFI_PEI_PPI_DESCRIPTOR)
514+
);
515+
PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
516+
PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
517+
PeiUsbDevice->UsbHcPpi = UsbHcPpi;
518+
PeiUsbDevice->Usb2HcPpi = Usb2HcPpi;
519+
PeiUsbDevice->IsHub = 0x0;
520+
PeiUsbDevice->DownStreamPortNo = 0x0;
521+
522+
if (((PortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0) ||
523+
((PortStatus.PortStatus & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) == 0))
524+
{
525+
//
526+
// If the port already has reset change flag and is connected and enabled, skip the port reset logic.
527+
//
528+
ResetRootPort (
529+
PeiServices,
530+
PeiUsbDevice->UsbHcPpi,
531+
PeiUsbDevice->Usb2HcPpi,
532+
Index,
533+
0
534+
);
535+
536+
if (Usb2HcPpi != NULL) {
537+
Usb2HcPpi->GetRootHubPortStatus (
538+
PeiServices,
539+
Usb2HcPpi,
540+
(UINT8)Index,
541+
&PortStatus
542+
);
543+
} else {
544+
UsbHcPpi->GetRootHubPortStatus (
545+
PeiServices,
546+
UsbHcPpi,
547+
(UINT8)Index,
548+
&PortStatus
549+
);
550+
}
551551
} else {
552-
UsbHcPpi->ClearRootHubPortFeature (
553-
PeiServices,
554-
UsbHcPpi,
555-
(UINT8)Index,
556-
EfiUsbPortResetChange
557-
);
552+
if (Usb2HcPpi != NULL) {
553+
Usb2HcPpi->ClearRootHubPortFeature (
554+
PeiServices,
555+
Usb2HcPpi,
556+
(UINT8)Index,
557+
EfiUsbPortResetChange
558+
);
559+
} else {
560+
UsbHcPpi->ClearRootHubPortFeature (
561+
PeiServices,
562+
UsbHcPpi,
563+
(UINT8)Index,
564+
EfiUsbPortResetChange
565+
);
566+
}
558567
}
559-
}
560568

561-
PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
562-
DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
569+
PeiUsbDevice->DeviceSpeed = (UINT8)PeiUsbGetDeviceSpeed (PortStatus.PortStatus);
570+
DEBUG ((DEBUG_INFO, "Device Speed =%d\n", PeiUsbDevice->DeviceSpeed));
563571

564-
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {
565-
PeiUsbDevice->MaxPacketSize0 = 512;
566-
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
567-
PeiUsbDevice->MaxPacketSize0 = 64;
568-
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
569-
PeiUsbDevice->MaxPacketSize0 = 8;
570-
} else {
571-
PeiUsbDevice->MaxPacketSize0 = 8;
572-
}
573-
574-
//
575-
// Configure that Usb Device
576-
//
577-
Status = PeiConfigureUsbDevice (
578-
PeiServices,
579-
PeiUsbDevice,
580-
Index,
581-
&CurrentAddress
582-
);
583-
584-
if (EFI_ERROR (Status)) {
585-
continue;
586-
}
587-
588-
DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
589-
590-
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
591-
592-
if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
593-
PeiUsbDevice->IsHub = 0x1;
594-
595-
Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
596-
if (EFI_ERROR (Status)) {
597-
return Status;
572+
if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_SUPER_SPEED)) {
573+
PeiUsbDevice->MaxPacketSize0 = 512;
574+
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_HIGH_SPEED)) {
575+
PeiUsbDevice->MaxPacketSize0 = 64;
576+
} else if (USB_BIT_IS_SET (PortStatus.PortStatus, USB_PORT_STAT_LOW_SPEED)) {
577+
PeiUsbDevice->MaxPacketSize0 = 8;
578+
} else {
579+
PeiUsbDevice->MaxPacketSize0 = 8;
598580
}
599581

600-
PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
601-
}
602-
603-
for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
604582
//
605-
// Begin to deal with the new device
583+
// Configure that Usb Device
606584
//
607-
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
608-
Status = PeiServicesAllocatePages (
609-
EfiBootServicesCode,
610-
MemPages,
611-
&AllocateAddress
612-
);
585+
Status = PeiConfigureUsbDevice (
586+
PeiServices,
587+
PeiUsbDevice,
588+
Index,
589+
&CurrentAddress
590+
);
591+
613592
if (EFI_ERROR (Status)) {
614-
return EFI_OUT_OF_RESOURCES;
593+
continue;
615594
}
616595

617-
CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE));
618-
PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
619-
PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
620-
PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
621-
PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex];
622-
for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
623-
PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
624-
}
596+
DEBUG ((DEBUG_INFO, "PeiUsbEnumeration: PeiConfigureUsbDevice Success\n"));
625597

626598
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
627599

@@ -635,11 +607,48 @@ PeiUsbEnumeration (
635607

636608
PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
637609
}
610+
611+
for (InterfaceIndex = 1; InterfaceIndex < PeiUsbDevice->ConfigDesc->NumInterfaces; InterfaceIndex++) {
612+
//
613+
// Begin to deal with the new device
614+
//
615+
MemPages = sizeof (PEI_USB_DEVICE) / EFI_PAGE_SIZE + 1;
616+
Status = PeiServicesAllocatePages (
617+
EfiBootServicesCode,
618+
MemPages,
619+
&AllocateAddress
620+
);
621+
if (EFI_ERROR (Status)) {
622+
return EFI_OUT_OF_RESOURCES;
623+
}
624+
625+
CopyMem ((VOID *)(UINTN)AllocateAddress, PeiUsbDevice, sizeof (PEI_USB_DEVICE));
626+
PeiUsbDevice = (PEI_USB_DEVICE *)((UINTN)AllocateAddress);
627+
PeiUsbDevice->AllocateAddress = (UINTN)AllocateAddress;
628+
PeiUsbDevice->UsbIoPpiList.Ppi = &PeiUsbDevice->UsbIoPpi;
629+
PeiUsbDevice->InterfaceDesc = PeiUsbDevice->InterfaceDescList[InterfaceIndex];
630+
for (EndpointIndex = 0; EndpointIndex < PeiUsbDevice->InterfaceDesc->NumEndpoints; EndpointIndex++) {
631+
PeiUsbDevice->EndpointDesc[EndpointIndex] = PeiUsbDevice->EndpointDescList[InterfaceIndex][EndpointIndex];
632+
}
633+
634+
Status = PeiServicesInstallPpi (&PeiUsbDevice->UsbIoPpiList);
635+
636+
if (PeiUsbDevice->InterfaceDesc->InterfaceClass == 0x09) {
637+
PeiUsbDevice->IsHub = 0x1;
638+
639+
Status = PeiDoHubConfig (PeiServices, PeiUsbDevice);
640+
if (EFI_ERROR (Status)) {
641+
return Status;
642+
}
643+
644+
PeiHubEnumeration (PeiServices, PeiUsbDevice, &CurrentAddress);
645+
}
646+
}
647+
} else {
648+
//
649+
// Disconnect change happen, currently we don't support
650+
//
638651
}
639-
} else {
640-
//
641-
// Disconnect change happen, currently we don't support
642-
//
643652
}
644653
}
645654
}

0 commit comments

Comments
 (0)