Skip to content

Commit

Permalink
MdeModulePkg/Bus/Pci/XhciDxe: Check port is compatible before getting…
Browse files Browse the repository at this point in the history
… PSIV

On some platforms, including Sky Lake and Kaby Lake, the PSIV (Protocol
Speed ID Value) indices are shared between Protocol Speed ID DWORD' in
the extended capabilities registers for both USB2 (Full Speed) and USB3
(Super Speed).

An example can be found below:

    XhcCheckUsbPortSpeedUsedPsic: checking for USB2 ext caps
    XhciPsivGetPsid: found 3 PSID entries
    XhciPsivGetPsid: looking for port speed 1
    XhciPsivGetPsid: PSIV 1 PSIE 2 PLT 0 PSIM 12
    XhciPsivGetPsid: PSIV 2 PSIE 1 PLT 0 PSIM 1500
    XhciPsivGetPsid: PSIV 3 PSIE 2 PLT 0 PSIM 480
    XhcCheckUsbPortSpeedUsedPsic: checking for USB3 ext caps
    XhciPsivGetPsid: found 3 PSID entries
    XhciPsivGetPsid: looking for port speed 1
    XhciPsivGetPsid: PSIV 1 PSIE 3 PLT 0 PSIM 5
    XhciPsivGetPsid: PSIV 2 PSIE 3 PLT 0 PSIM 10
    XhciPsivGetPsid: PSIV 34 PSIE 2 PLT 0 PSIM 1248

The result is edk2 detecting USB2 devices as USB3 devices, which
consequently causes enumeration to fail.

To avoid incorrect detection, check the Compatible Port Offset to find
the starting Port of Root Hubs that support the protocol.

Signed-off-by: Sean Rhodes <sean@starlabs.systems>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
  • Loading branch information
Sean-StarLabs authored and mergify[bot] committed Dec 21, 2022
1 parent 01c2fb0 commit ec25e90
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 11 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 @@ -405,7 +405,7 @@ XhcGetRootHubPortStatus (
// Section 7.2 xHCI Support Protocol Capability
//
if (PortSpeed > 0) {
PortStatus->PortStatus = XhcCheckUsbPortSpeedUsedPsic (Xhc, PortSpeed);
PortStatus->PortStatus = XhcCheckUsbPortSpeedUsedPsic (Xhc, PortSpeed, PortNumber);
// If no match found in ext cap reg, fall back to PORTSC
if (PortStatus->PortStatus == 0) {
//
Expand Down
35 changes: 29 additions & 6 deletions MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ XhcGetSupportedProtocolCapabilityAddr (
@param Xhc The XHCI Instance.
@param ExtCapOffset The USB Major Version in xHCI Support Protocol Capability Field
@param PortSpeed The Port Speed Field in USB PortSc register
@param PortNumber The Port Number (0-indexed)
@return The Protocol Speed ID (PSI) from xHCI Supported Protocol capability register.
Expand All @@ -644,12 +645,15 @@ UINT32
XhciPsivGetPsid (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT32 ExtCapOffset,
IN UINT8 PortSpeed
IN UINT8 PortSpeed,
IN UINT8 PortNumber
)
{
XHC_SUPPORTED_PROTOCOL_DW2 PortId;
XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID Reg;
UINT32 Count;
UINT32 MinPortIndex;
UINT32 MaxPortIndex;

if ((Xhc == NULL) || (ExtCapOffset == 0xFFFFFFFF)) {
return 0;
Expand All @@ -663,6 +667,23 @@ XhciPsivGetPsid (
//
PortId.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_DW2_OFFSET);

//
// According to XHCI 1.1 spec November 2017, valid values
// for CompPortOffset are 1 to CompPortCount - 1.
//
// PortNumber is zero-indexed, so subtract 1.
//
if ((PortId.Data.CompPortOffset == 0) || (PortId.Data.CompPortCount == 0)) {
return 0;
}

MinPortIndex = PortId.Data.CompPortOffset - 1;
MaxPortIndex = MinPortIndex + PortId.Data.CompPortCount - 1;

if ((PortNumber < MinPortIndex) || (PortNumber > MaxPortIndex)) {
return 0;
}

for (Count = 0; Count < PortId.Data.Psic; Count++) {
Reg.Dword = XhcReadExtCapReg (Xhc, ExtCapOffset + XHC_SUPPORTED_PROTOCOL_PSI_OFFSET + (Count << 2));
if (Reg.Data.Psiv == PortSpeed) {
Expand All @@ -676,16 +697,18 @@ XhciPsivGetPsid (
/**
Find PortSpeed value match case in XHCI Supported Protocol Capability
@param Xhc The XHCI Instance.
@param PortSpeed The Port Speed Field in USB PortSc register
@param Xhc The XHCI Instance.
@param PortSpeed The Port Speed Field in USB PortSc register
@param PortNumber The Port Number (0-indexed)
@return The USB Port Speed.
**/
UINT16
XhcCheckUsbPortSpeedUsedPsic (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT8 PortSpeed
IN UINT8 PortSpeed,
IN UINT8 PortNumber
)
{
XHC_SUPPORTED_PROTOCOL_PROTOCOL_SPEED_ID SpField;
Expand All @@ -703,7 +726,7 @@ XhcCheckUsbPortSpeedUsedPsic (
// PortSpeed definition when the Major Revision is 03h.
//
if (Xhc->Usb3SupOffset != 0xFFFFFFFF) {
SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb3SupOffset, PortSpeed);
SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb3SupOffset, PortSpeed, PortNumber);
if (SpField.Dword != 0) {
//
// Found the corresponding PORTSC value in PSIV field of USB3 offset.
Expand All @@ -717,7 +740,7 @@ XhcCheckUsbPortSpeedUsedPsic (
// PortSpeed definition when the Major Revision is 02h.
//
if ((UsbSpeedIdMap == 0) && (Xhc->Usb2SupOffset != 0xFFFFFFFF)) {
SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb2SupOffset, PortSpeed);
SpField.Dword = XhciPsivGetPsid (Xhc, Xhc->Usb2SupOffset, PortSpeed, PortNumber);
if (SpField.Dword != 0) {
//
// Found the corresponding PORTSC value in PSIV field of USB2 offset.
Expand Down
10 changes: 6 additions & 4 deletions MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.h
Original file line number Diff line number Diff line change
Expand Up @@ -621,18 +621,20 @@ XhcGetSupportedProtocolCapabilityAddr (
);

/**
Find SpeedField value match with Port Speed ID value.
Find PortSpeed value match case in XHCI Supported Protocol Capability
@param Xhc The XHCI Instance.
@param Speed The Port Speed filed in USB PortSc register
@param Xhc The XHCI Instance.
@param PortSpeed The Port Speed Field in USB PortSc register
@param PortNumber The Port Number (0-indexed)
@return The USB Port Speed.
**/
UINT16
XhcCheckUsbPortSpeedUsedPsic (
IN USB_XHCI_INSTANCE *Xhc,
IN UINT8 Speed
IN UINT8 PortSpeed,
IN UINT8 PortNumber
);

#endif

0 comments on commit ec25e90

Please sign in to comment.