diff options
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 11 |
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); |