* [PATCH v3 2/3] xhci: Set URB actual length for stopped control transfers
[not found] <1490705730-23411-1-git-send-email-mathias.nyman@linux.intel.com>
@ 2017-03-28 12:55 ` Mathias Nyman
2017-03-28 12:55 ` [PATCH v3 3/3] xhci: Manually give back cancelled URB if we can't queue it for cancel Mathias Nyman
1 sibling, 0 replies; 2+ messages in thread
From: Mathias Nyman @ 2017-03-28 12:55 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, Mathias Nyman, stable
A control transfer that stopped at the status stage incorrectly
warned about a "unexpected TRB Type 4", and did not set the
transferred actual_length for the URB.
The URB actual_length for control transfers should contain the
bytes transferred in the data stage.
Bytes of a partially sent setup stage and missing bytes from
status stage should be left out.
Cc: <stable@vger.kernel.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci-ring.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index d9936c7..a3309aa 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1989,6 +1989,9 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
case TRB_NORMAL:
td->urb->actual_length = requested - remaining;
goto finish_td;
+ case TRB_STATUS:
+ td->urb->actual_length = requested;
+ goto finish_td;
default:
xhci_warn(xhci, "WARN: unexpected TRB Type %d\n",
trb_type);
--
1.9.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH v3 3/3] xhci: Manually give back cancelled URB if we can't queue it for cancel
[not found] <1490705730-23411-1-git-send-email-mathias.nyman@linux.intel.com>
2017-03-28 12:55 ` [PATCH v3 2/3] xhci: Set URB actual length for stopped control transfers Mathias Nyman
@ 2017-03-28 12:55 ` Mathias Nyman
1 sibling, 0 replies; 2+ messages in thread
From: Mathias Nyman @ 2017-03-28 12:55 UTC (permalink / raw)
To: gregkh; +Cc: linux-usb, Mathias Nyman, stable
xhci needs to take care of four scenarios when asked to cancel a URB.
1 URB is not queued or already given back.
usb_hcd_check_unlink_urb() will return an error, we pass the error on
2 We fail to find xhci internal structures from urb private data such as
virtual device and endpoint ring.
Give back URB immediately, can't do anything about internal structures.
3 URB private data has valid pointers to xhci internal data, but host is
not responding.
give back URB immedately and remove the URB from the endpoint lists.
4 Everyting is working
add URB to cancel list, queue a command to stop the endpoint, after
which the URB can be turned to no-op or skipped, removed from lists,
and given back.
We failed to give back the urb in case 2 where the correct device and
endpoint pointers could not be retrieved from URB private data.
This caused a hang on Dell Inspiron 5558/0VNM2T at resume from suspend
as urb was never returned.
[ 245.270505] INFO: task rtsx_usb_ms_1:254 blocked for more than 120 seconds.
[ 245.272244] Tainted: G W 4.11.0-rc3-ARCH #2
[ 245.273983] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[ 245.275737] rtsx_usb_ms_1 D 0 254 2 0x00000000
[ 245.277524] Call Trace:
[ 245.279278] __schedule+0x2d3/0x8a0
[ 245.281077] schedule+0x3d/0x90
[ 245.281961] usb_kill_urb.part.3+0x6c/0xa0 [usbcore]
[ 245.282861] ? wake_atomic_t_function+0x60/0x60
[ 245.283760] usb_kill_urb+0x21/0x30 [usbcore]
[ 245.284649] usb_start_wait_urb+0xe5/0x170 [usbcore]
[ 245.285541] ? try_to_del_timer_sync+0x53/0x80
[ 245.286434] usb_bulk_msg+0xbd/0x160 [usbcore]
[ 245.287326] rtsx_usb_send_cmd+0x63/0x90 [rtsx_usb]
Reported-by: diego.viola@gmail.com
Tested-by: diego.viola@gmail.com
Cc: stable@vger.kernel.org
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
---
drivers/usb/host/xhci.c | 43 +++++++++++++++++++++++++------------------
1 file changed, 25 insertions(+), 18 deletions(-)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 50aee8b..953fd8f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1477,6 +1477,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
struct xhci_ring *ep_ring;
struct xhci_virt_ep *ep;
struct xhci_command *command;
+ struct xhci_virt_device *vdev;
xhci = hcd_to_xhci(hcd);
spin_lock_irqsave(&xhci->lock, flags);
@@ -1485,15 +1486,27 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/* Make sure the URB hasn't completed or been unlinked already */
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
- if (ret || !urb->hcpriv)
+ if (ret)
goto done;
+
+ /* give back URB now if we can't queue it for cancel */
+ vdev = xhci->devs[urb->dev->slot_id];
+ urb_priv = urb->hcpriv;
+ if (!vdev || !urb_priv)
+ goto err_giveback;
+
+ ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+ ep = &vdev->eps[ep_index];
+ ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+ if (!ep || !ep_ring)
+ goto err_giveback;
+
temp = readl(&xhci->op_regs->status);
if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"HW died, freeing TD.");
- urb_priv = urb->hcpriv;
for (i = urb_priv->num_tds_done;
- i < urb_priv->num_tds && xhci->devs[urb->dev->slot_id];
+ i < urb_priv->num_tds;
i++) {
td = &urb_priv->td[i];
if (!list_empty(&td->td_list))
@@ -1501,23 +1514,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (!list_empty(&td->cancelled_td_list))
list_del_init(&td->cancelled_td_list);
}
-
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock_irqrestore(&xhci->lock, flags);
- usb_hcd_giveback_urb(hcd, urb, -ESHUTDOWN);
- xhci_urb_free_priv(urb_priv);
- return ret;
+ goto err_giveback;
}
- ep_index = xhci_get_endpoint_index(&urb->ep->desc);
- ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
- ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
- if (!ep_ring) {
- ret = -EINVAL;
- goto done;
- }
-
- urb_priv = urb->hcpriv;
i = urb_priv->num_tds_done;
if (i < urb_priv->num_tds)
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
@@ -1554,6 +1553,14 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
done:
spin_unlock_irqrestore(&xhci->lock, flags);
return ret;
+
+err_giveback:
+ if (urb_priv)
+ xhci_urb_free_priv(urb_priv);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ usb_hcd_giveback_urb(hcd, urb, -ESHUTDOWN);
+ return ret;
}
/* Drop an endpoint from a new bandwidth configuration for this device.
--
1.9.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2017-03-28 13:01 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1490705730-23411-1-git-send-email-mathias.nyman@linux.intel.com>
2017-03-28 12:55 ` [PATCH v3 2/3] xhci: Set URB actual length for stopped control transfers Mathias Nyman
2017-03-28 12:55 ` [PATCH v3 3/3] xhci: Manually give back cancelled URB if we can't queue it for cancel Mathias Nyman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).