diff options
| author | Felipe Balbi <felipe.balbi@linux.intel.com> | 2017-01-03 11:28:53 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-01-03 11:37:32 -0500 |
| commit | 29fc1aa454d0603493b47a8e2410ae6e9ab20258 (patch) | |
| tree | b3043688b5e5ac95ea3e9b9398b9726f3be4565a | |
| parent | 6c97cfc1a097b1e0786c836e92b7a72b4d031e25 (diff) | |
usb: host: xhci: handle COMP_STOP from SETUP phase too
Stop Endpoint command can come at any point and we
have no control of that. We should make sure to
handle COMP_STOP on SETUP phase as well, otherwise
urb->actual_length might be set to negative values
in some occasions such as below:
urb->length = 4;
build_control_transfer_td_for(urb, ep);
stop_endpoint(ep);
COMP_STOP:
[...]
urb->actual_length = urb->length - trb->length;
trb->length is 8 for SETUP stage (8 control request
bytes), so actual_length would be set to -4 in this
case.
While doing that, also make sure to use TRB_TYPE
field of the actual TRB instead of matching pointers
to figure out in which stage of the control transfer
we got our completion event.
Cc: <stable@vger.kernel.org>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/usb/host/xhci-ring.c | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 7a14e9ad664d..25f522b09dd9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
| @@ -1971,8 +1971,9 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
| 1971 | struct xhci_ep_ctx *ep_ctx; | 1971 | struct xhci_ep_ctx *ep_ctx; |
| 1972 | u32 trb_comp_code; | 1972 | u32 trb_comp_code; |
| 1973 | u32 remaining, requested; | 1973 | u32 remaining, requested; |
| 1974 | bool on_data_stage; | 1974 | u32 trb_type; |
| 1975 | 1975 | ||
| 1976 | trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(ep_trb->generic.field[3])); | ||
| 1976 | slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); | 1977 | slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); |
| 1977 | xdev = xhci->devs[slot_id]; | 1978 | xdev = xhci->devs[slot_id]; |
| 1978 | ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; | 1979 | ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; |
| @@ -1982,14 +1983,11 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
| 1982 | requested = td->urb->transfer_buffer_length; | 1983 | requested = td->urb->transfer_buffer_length; |
| 1983 | remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); | 1984 | remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); |
| 1984 | 1985 | ||
| 1985 | /* not setup (dequeue), or status stage means we are at data stage */ | ||
| 1986 | on_data_stage = (ep_trb != ep_ring->dequeue && ep_trb != td->last_trb); | ||
| 1987 | |||
| 1988 | switch (trb_comp_code) { | 1986 | switch (trb_comp_code) { |
| 1989 | case COMP_SUCCESS: | 1987 | case COMP_SUCCESS: |
| 1990 | if (ep_trb != td->last_trb) { | 1988 | if (trb_type != TRB_STATUS) { |
| 1991 | xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n", | 1989 | xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n", |
| 1992 | on_data_stage ? "data" : "setup"); | 1990 | (trb_type == TRB_DATA) ? "data" : "setup"); |
| 1993 | *status = -ESHUTDOWN; | 1991 | *status = -ESHUTDOWN; |
| 1994 | break; | 1992 | break; |
| 1995 | } | 1993 | } |
| @@ -1999,15 +1997,25 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
| 1999 | *status = 0; | 1997 | *status = 0; |
| 2000 | break; | 1998 | break; |
| 2001 | case COMP_STOP_SHORT: | 1999 | case COMP_STOP_SHORT: |
| 2002 | if (on_data_stage) | 2000 | if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) |
| 2003 | td->urb->actual_length = remaining; | 2001 | td->urb->actual_length = remaining; |
| 2004 | else | 2002 | else |
| 2005 | xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); | 2003 | xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); |
| 2006 | goto finish_td; | 2004 | goto finish_td; |
| 2007 | case COMP_STOP: | 2005 | case COMP_STOP: |
| 2008 | if (on_data_stage) | 2006 | switch (trb_type) { |
| 2007 | case TRB_SETUP: | ||
| 2008 | td->urb->actual_length = 0; | ||
| 2009 | goto finish_td; | ||
| 2010 | case TRB_DATA: | ||
| 2011 | case TRB_NORMAL: | ||
| 2009 | td->urb->actual_length = requested - remaining; | 2012 | td->urb->actual_length = requested - remaining; |
| 2010 | goto finish_td; | 2013 | goto finish_td; |
| 2014 | default: | ||
| 2015 | xhci_warn(xhci, "WARN: unexpected TRB Type %d\n", | ||
| 2016 | trb_type); | ||
| 2017 | goto finish_td; | ||
| 2018 | } | ||
| 2011 | case COMP_STOP_INVAL: | 2019 | case COMP_STOP_INVAL: |
| 2012 | goto finish_td; | 2020 | goto finish_td; |
| 2013 | default: | 2021 | default: |
| @@ -2019,7 +2027,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
| 2019 | /* else fall through */ | 2027 | /* else fall through */ |
| 2020 | case COMP_STALL: | 2028 | case COMP_STALL: |
| 2021 | /* Did we transfer part of the data (middle) phase? */ | 2029 | /* Did we transfer part of the data (middle) phase? */ |
| 2022 | if (on_data_stage) | 2030 | if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) |
| 2023 | td->urb->actual_length = requested - remaining; | 2031 | td->urb->actual_length = requested - remaining; |
| 2024 | else if (!td->urb_length_set) | 2032 | else if (!td->urb_length_set) |
| 2025 | td->urb->actual_length = 0; | 2033 | td->urb->actual_length = 0; |
| @@ -2027,14 +2035,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
| 2027 | } | 2035 | } |
| 2028 | 2036 | ||
| 2029 | /* stopped at setup stage, no data transferred */ | 2037 | /* stopped at setup stage, no data transferred */ |
| 2030 | if (ep_trb == ep_ring->dequeue) | 2038 | if (trb_type == TRB_SETUP) |
| 2031 | goto finish_td; | 2039 | goto finish_td; |
| 2032 | 2040 | ||
| 2033 | /* | 2041 | /* |
| 2034 | * if on data stage then update the actual_length of the URB and flag it | 2042 | * if on data stage then update the actual_length of the URB and flag it |
| 2035 | * as set, so it won't be overwritten in the event for the last TRB. | 2043 | * as set, so it won't be overwritten in the event for the last TRB. |
| 2036 | */ | 2044 | */ |
| 2037 | if (on_data_stage) { | 2045 | if (trb_type == TRB_DATA || |
| 2046 | trb_type == TRB_NORMAL) { | ||
| 2038 | td->urb_length_set = true; | 2047 | td->urb_length_set = true; |
| 2039 | td->urb->actual_length = requested - remaining; | 2048 | td->urb->actual_length = requested - remaining; |
| 2040 | xhci_dbg(xhci, "Waiting for status stage event\n"); | 2049 | xhci_dbg(xhci, "Waiting for status stage event\n"); |
