]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[xhci] Assume an invalid PSI table if any invalid PSI value is observed
authorMichael Brown <mcb30@ipxe.org>
Mon, 29 Jan 2018 21:25:11 +0000 (21:25 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 29 Jan 2018 21:28:12 +0000 (21:28 +0000)
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>
src/drivers/usb/xhci.c

index 825171a52509d5904d0e252ad5096891a5357b9c..8bf3ca776d0a9742c4919cd8d2c1207d88403076 100644 (file)
@@ -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;
+       }
 }
 
 /**