Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[xhci] Assume an invalid PSI table if any invalid PSI value is observed
Invalid protocol speed ID tables appear to be increasingly common in
the wild, to the point that it is infeasible to apply an explicit
XHCI_BAD_PSIV flag for each offending PCI device ID.

Fix by assuming an invalid PSI table as soon as any invalid value is
reported by the hardware.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Jan 29, 2018
1 parent fbe8c52 commit c900751
Showing 1 changed file with 30 additions and 23 deletions.
53 changes: 30 additions & 23 deletions src/drivers/usb/xhci.c
Expand Up @@ -801,34 +801,41 @@ static int xhci_port_speed ( struct xhci_device *xhci, unsigned int port,
ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );

/* Use the default mappings if applicable */
if ( ( psic == 0 ) || ( xhci->quirks & XHCI_BAD_PSIV ) ) {
switch ( psiv ) {
case XHCI_SPEED_LOW : return USB_SPEED_LOW;
case XHCI_SPEED_FULL : return USB_SPEED_FULL;
case XHCI_SPEED_HIGH : return USB_SPEED_HIGH;
case XHCI_SPEED_SUPER : return USB_SPEED_SUPER;
default:
DBGC ( xhci, "XHCI %s-%d non-standard PSI value %d\n",
xhci->name, port, psiv );
return -ENOTSUP;
/* Use protocol speed ID table unless device is known to be faulty */
if ( ! ( xhci->quirks & XHCI_BAD_PSIV ) ) {

/* Iterate over PSI dwords looking for a match */
for ( i = 0 ; i < psic ; i++ ) {
psi = readl ( xhci->cap + supported +
XHCI_SUPPORTED_PSI ( i ) );
if ( psiv == XHCI_SUPPORTED_PSI_VALUE ( psi ) ) {
mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
speed = USB_SPEED ( mantissa, exponent );
return speed;
}
}
}

/* Iterate over PSI dwords looking for a match */
for ( i = 0 ; i < psic ; i++ ) {
psi = readl ( xhci->cap + supported + XHCI_SUPPORTED_PSI ( i ));
if ( psiv == XHCI_SUPPORTED_PSI_VALUE ( psi ) ) {
mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
speed = USB_SPEED ( mantissa, exponent );
return speed;
/* Record device as faulty if no match is found */
if ( psic != 0 ) {
DBGC ( xhci, "XHCI %s-%d spurious PSI value %d: "
"assuming PSI table is invalid\n",
xhci->name, port, psiv );
xhci->quirks |= XHCI_BAD_PSIV;
}
}

DBGC ( xhci, "XHCI %s-%d spurious PSI value %d\n",
xhci->name, port, psiv );
return -ENOENT;
/* Use the default mappings */
switch ( psiv ) {
case XHCI_SPEED_LOW : return USB_SPEED_LOW;
case XHCI_SPEED_FULL : return USB_SPEED_FULL;
case XHCI_SPEED_HIGH : return USB_SPEED_HIGH;
case XHCI_SPEED_SUPER : return USB_SPEED_SUPER;
default:
DBGC ( xhci, "XHCI %s-%d unrecognised PSI value %d\n",
xhci->name, port, psiv );
return -ENOTSUP;
}
}

/**
Expand Down

0 comments on commit c900751

Please sign in to comment.