|
@@ -37,6 +37,21 @@ static unsigned long long quirks;
|
|
|
module_param(quirks, ullong, S_IRUGO);
|
|
|
MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
|
|
|
|
|
|
+static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring)
|
|
|
+{
|
|
|
+ struct xhci_segment *seg = ring->first_seg;
|
|
|
+
|
|
|
+ if (!td || !td->start_seg)
|
|
|
+ return false;
|
|
|
+ do {
|
|
|
+ if (seg == td->start_seg)
|
|
|
+ return true;
|
|
|
+ seg = seg->next;
|
|
|
+ } while (seg && seg != ring->first_seg);
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
/* TODO: copied from ehci-hcd.c - can this be refactored? */
|
|
|
/*
|
|
|
* xhci_handshake - spin reading hc until handshake completes or fails
|
|
@@ -1571,6 +1586,21 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
|
|
goto done;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * check ring is not re-allocated since URB was enqueued. If it is, then
|
|
|
+ * make sure none of the ring related pointers in this URB private data
|
|
|
+ * are touched, such as td_list, otherwise we overwrite freed data
|
|
|
+ */
|
|
|
+ if (!td_on_ring(&urb_priv->td[0], ep_ring)) {
|
|
|
+ xhci_err(xhci, "Canceled URB td not found on endpoint ring");
|
|
|
+ for (i = urb_priv->num_tds_done; i < urb_priv->num_tds; i++) {
|
|
|
+ td = &urb_priv->td[i];
|
|
|
+ if (!list_empty(&td->cancelled_td_list))
|
|
|
+ list_del_init(&td->cancelled_td_list);
|
|
|
+ }
|
|
|
+ goto err_giveback;
|
|
|
+ }
|
|
|
+
|
|
|
if (xhci->xhc_state & XHCI_STATE_HALTED) {
|
|
|
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
|
|
|
"HC halted, freeing TD manually.");
|