summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb
diff options
context:
space:
mode:
authorMichael Brown2018-01-29 22:25:11 +0100
committerMichael Brown2018-01-29 22:28:12 +0100
commitc900751fa65c35f0975e103fce3c17d8c40aa270 (patch)
treeb5596287993ecb9c507d012f15a8f0619a0d9831 /src/drivers/usb
parent[ena] Fix spurious uninitialised variable warning on older versions of gcc (diff)
downloadipxe-c900751fa65c35f0975e103fce3c17d8c40aa270.tar.gz
ipxe-c900751fa65c35f0975e103fce3c17d8c40aa270.tar.xz
ipxe-c900751fa65c35f0975e103fce3c17d8c40aa270.zip
[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>
Diffstat (limited to 'src/drivers/usb')
-rw-r--r--src/drivers/usb/xhci.c53
1 files changed, 30 insertions, 23 deletions
diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c
index 825171a5..8bf3ca77 100644
--- a/src/drivers/usb/xhci.c
+++ b/src/drivers/usb/xhci.c
@@ -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;
+ }
}
/**