Skip to content

Commit

Permalink
Reset USB port during enumeration if GetPortStatus returns device err…
Browse files Browse the repository at this point in the history
…or (#101)

During USB device enumeration, issuing a hot reset on a port is skipped if there
is a reset change status already detected on the port. This can happen when
enumerating devices after a host controller soft reset (which drives a hot reset
down the ports).

However, in certain cases an attached device may not be responsive even if the
reset change and connection status bits are set. For e.g., according to xHCI
spec section 4.19.5.1 the port reset change bits can be set when a hot reset
driven on the port transitions to a warm reset and completes with errors. For
such instances it is worthwhile to force a hot reset during enumeration to try
and recover unresponsive devices.

During enumeration check whether querying port status returns EFI_DEVICE_ERROR
and try a port reset if there is a device attached to the port.

Co-authored-by: Alok Kulkarni <akulkarni@microsoft.com>
  • Loading branch information
2 people authored and kenlautner committed Sep 20, 2022
1 parent d89de92 commit 1df7966
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 3 deletions.
2 changes: 1 addition & 1 deletion MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ XhcGetRootHubPortStatus (
// For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
//
ParentRouteChart.Dword = 0;
XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
Status = XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus); // MU_CHANGE

ON_EXIT:
gBS->RestoreTPL (OldTpl);
Expand Down
12 changes: 10 additions & 2 deletions MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c
Original file line number Diff line number Diff line change
Expand Up @@ -908,12 +908,18 @@ UsbEnumeratePort (
Child = NULL;
HubApi = HubIf->HubApi;

// MU_CHANGE: Zero out PortState in case GetPortStatus does not set it and we
// continue on the EFI_DEVICE_ERROR path
PortState.PortStatus = 0;
PortState.PortChangeStatus = 0;

//
// Host learns of the new device by polling the hub for port changes.
//
Status = HubApi->GetPortStatus (HubIf, Port, &PortState);

if (EFI_ERROR (Status)) {
// MU_CHANGE - try a port reset if GetPortStatus returns device error
if (EFI_ERROR (Status) && (Status != EFI_DEVICE_ERROR)) {
DEBUG ((DEBUG_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port));
return Status;
}
Expand Down Expand Up @@ -995,7 +1001,9 @@ UsbEnumeratePort (
// Now, new device connected, enumerate and configure the device
//
DEBUG ((DEBUG_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port));
if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET) &&
(Status != EFI_DEVICE_ERROR)) // MU_CHANGE
{
Status = UsbEnumerateNewDev (HubIf, Port, FALSE);
} else {
Status = UsbEnumerateNewDev (HubIf, Port, TRUE);
Expand Down

0 comments on commit 1df7966

Please sign in to comment.