aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/xhci-ring.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b69a0a136e66..b0b4cc3b8584 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1235,6 +1235,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
1235 u8 major_revision; 1235 u8 major_revision;
1236 struct xhci_bus_state *bus_state; 1236 struct xhci_bus_state *bus_state;
1237 u32 __iomem **port_array; 1237 u32 __iomem **port_array;
1238 bool bogus_port_status = false;
1238 1239
1239 /* Port status change events always have a successful completion code */ 1240 /* Port status change events always have a successful completion code */
1240 if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) { 1241 if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
@@ -1247,6 +1248,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
1247 max_ports = HCS_MAX_PORTS(xhci->hcs_params1); 1248 max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
1248 if ((port_id <= 0) || (port_id > max_ports)) { 1249 if ((port_id <= 0) || (port_id > max_ports)) {
1249 xhci_warn(xhci, "Invalid port id %d\n", port_id); 1250 xhci_warn(xhci, "Invalid port id %d\n", port_id);
1251 bogus_port_status = true;
1250 goto cleanup; 1252 goto cleanup;
1251 } 1253 }
1252 1254
@@ -1258,12 +1260,14 @@ static void handle_port_status(struct xhci_hcd *xhci,
1258 xhci_warn(xhci, "Event for port %u not in " 1260 xhci_warn(xhci, "Event for port %u not in "
1259 "Extended Capabilities, ignoring.\n", 1261 "Extended Capabilities, ignoring.\n",
1260 port_id); 1262 port_id);
1263 bogus_port_status = true;
1261 goto cleanup; 1264 goto cleanup;
1262 } 1265 }
1263 if (major_revision == DUPLICATE_ENTRY) { 1266 if (major_revision == DUPLICATE_ENTRY) {
1264 xhci_warn(xhci, "Event for port %u duplicated in" 1267 xhci_warn(xhci, "Event for port %u duplicated in"
1265 "Extended Capabilities, ignoring.\n", 1268 "Extended Capabilities, ignoring.\n",
1266 port_id); 1269 port_id);
1270 bogus_port_status = true;
1267 goto cleanup; 1271 goto cleanup;
1268 } 1272 }
1269 1273
@@ -1335,6 +1339,13 @@ cleanup:
1335 /* Update event ring dequeue pointer before dropping the lock */ 1339 /* Update event ring dequeue pointer before dropping the lock */
1336 inc_deq(xhci, xhci->event_ring, true); 1340 inc_deq(xhci, xhci->event_ring, true);
1337 1341
1342 /* Don't make the USB core poll the roothub if we got a bad port status
1343 * change event. Besides, at that point we can't tell which roothub
1344 * (USB 2.0 or USB 3.0) to kick.
1345 */
1346 if (bogus_port_status)
1347 return;
1348
1338 spin_unlock(&xhci->lock); 1349 spin_unlock(&xhci->lock);
1339 /* Pass this up to the core */ 1350 /* Pass this up to the core */
1340 usb_hcd_poll_rh_status(hcd); 1351 usb_hcd_poll_rh_status(hcd);