if (skip)
goto td_cleanup;
- if (trb_comp_code == COMP_STOP_INVAL || trb_comp_code == COMP_STOP) {
+ if (trb_comp_code == COMP_STOP_INVAL ||
+ trb_comp_code == COMP_STOP ||
+ trb_comp_code == COMP_STOP_SHORT) {
/* The Endpoint Stop Command completion will take care of any
* stopped TDs. A stopped TD may be restarted, so don't update
* the ring dequeue pointer or take this TD off any lists yet.
else
*status = 0;
break;
- case COMP_STOP_INVAL:
+ case COMP_STOP_SHORT:
+ if (event_trb == ep_ring->dequeue || event_trb == td->last_trb)
+ xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n");
+ else
+ td->urb->actual_length =
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
+
+ return finish_td(xhci, td, event_trb, event, ep, status, false);
case COMP_STOP:
+ /* Did we stop at data stage? */
+ if (event_trb != ep_ring->dequeue && event_trb != td->last_trb)
+ td->urb->actual_length =
+ td->urb->transfer_buffer_length -
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
+ /* fall through */
+ case COMP_STOP_INVAL:
return finish_td(xhci, td, event_trb, event, ep, status, false);
default:
if (!xhci_requires_manual_halt_cleanup(xhci,
}
if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
trb_comp_code = COMP_SHORT_TX;
+ /* fallthrough */
+ case COMP_STOP_SHORT:
case COMP_SHORT_TX:
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
-EREMOTEIO : 0;
if (trb_comp_code == COMP_SUCCESS || skip_td) {
frame->actual_length = frame->length;
td->urb->actual_length += frame->length;
+ } else if (trb_comp_code == COMP_STOP_SHORT) {
+ frame->actual_length =
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
+ td->urb->actual_length += frame->actual_length;
} else {
for (cur_trb = ep_ring->dequeue,
cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
*status = 0;
}
break;
+ case COMP_STOP_SHORT:
case COMP_SHORT_TX:
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
*status = -EREMOTEIO;
td->urb->ep->desc.bEndpointAddress,
td->urb->transfer_buffer_length,
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
+ /* Stopped - short packet completion */
+ if (trb_comp_code == COMP_STOP_SHORT) {
+ td->urb->actual_length =
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
+
+ if (td->urb->transfer_buffer_length <
+ td->urb->actual_length) {
+ xhci_warn(xhci, "HC gave bad length of %d bytes txed\n",
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
+ td->urb->actual_length = 0;
+ /* status will be set by usb core for canceled urbs */
+ }
/* Fast path - was this the last TRB in the TD for this URB? */
- if (event_trb == td->last_trb) {
+ } else if (event_trb == td->last_trb) {
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
td->urb->actual_length =
td->urb->transfer_buffer_length -
case COMP_STOP_INVAL:
xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
break;
+ case COMP_STOP_SHORT:
+ xhci_dbg(xhci, "Stopped with short packet transfer detected\n");
+ break;
case COMP_STALL:
xhci_dbg(xhci, "Stalled endpoint\n");
ep->ep_state |= EP_HALTED;
#define HCC_LTC(p) ((p) & (1 << 6))
/* true: no secondary Stream ID Support */
#define HCC_NSS(p) ((p) & (1 << 7))
+/* true: HC supports Stopped - Short Packet */
+#define HCC_SPC(p) ((p) & (1 << 9))
/* true: HC has Contiguous Frame ID Capability */
#define HCC_CFC(p) ((p) & (1 << 11))
/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
#define COMP_STOP 26
/* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */
#define COMP_STOP_INVAL 27
-/* Control Abort Error - Debug Capability - control pipe aborted */
-#define COMP_DBG_ABORT 28
+/* Same as COMP_EP_STOPPED, but a short packet detected */
+#define COMP_STOP_SHORT 28
/* Max Exit Latency Too Large Error */
#define COMP_MEL_ERR 29
/* TRB type 30 reserved */