|
@@ -1812,7 +1812,9 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|
if (skip)
|
|
if (skip)
|
|
goto td_cleanup;
|
|
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
|
|
/* The Endpoint Stop Command completion will take care of any
|
|
* stopped TDs. A stopped TD may be restarted, so don't update
|
|
* stopped TDs. A stopped TD may be restarted, so don't update
|
|
* the ring dequeue pointer or take this TD off any lists yet.
|
|
* the ring dequeue pointer or take this TD off any lists yet.
|
|
@@ -1919,8 +1921,22 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|
else
|
|
else
|
|
*status = 0;
|
|
*status = 0;
|
|
break;
|
|
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:
|
|
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);
|
|
return finish_td(xhci, td, event_trb, event, ep, status, false);
|
|
default:
|
|
default:
|
|
if (!xhci_requires_manual_halt_cleanup(xhci,
|
|
if (!xhci_requires_manual_halt_cleanup(xhci,
|
|
@@ -2014,6 +2030,8 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|
}
|
|
}
|
|
if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
|
|
if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
|
|
trb_comp_code = COMP_SHORT_TX;
|
|
trb_comp_code = COMP_SHORT_TX;
|
|
|
|
+ /* fallthrough */
|
|
|
|
+ case COMP_STOP_SHORT:
|
|
case COMP_SHORT_TX:
|
|
case COMP_SHORT_TX:
|
|
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
|
|
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
|
|
-EREMOTEIO : 0;
|
|
-EREMOTEIO : 0;
|
|
@@ -2049,6 +2067,10 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|
if (trb_comp_code == COMP_SUCCESS || skip_td) {
|
|
if (trb_comp_code == COMP_SUCCESS || skip_td) {
|
|
frame->actual_length = frame->length;
|
|
frame->actual_length = frame->length;
|
|
td->urb->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 {
|
|
} else {
|
|
for (cur_trb = ep_ring->dequeue,
|
|
for (cur_trb = ep_ring->dequeue,
|
|
cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
|
|
cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
|
|
@@ -2129,6 +2151,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|
*status = 0;
|
|
*status = 0;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
|
|
+ case COMP_STOP_SHORT:
|
|
case COMP_SHORT_TX:
|
|
case COMP_SHORT_TX:
|
|
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
|
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
|
*status = -EREMOTEIO;
|
|
*status = -EREMOTEIO;
|
|
@@ -2145,8 +2168,20 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
|
td->urb->ep->desc.bEndpointAddress,
|
|
td->urb->ep->desc.bEndpointAddress,
|
|
td->urb->transfer_buffer_length,
|
|
td->urb->transfer_buffer_length,
|
|
EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
|
|
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? */
|
|
/* 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) {
|
|
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
|
|
td->urb->actual_length =
|
|
td->urb->actual_length =
|
|
td->urb->transfer_buffer_length -
|
|
td->urb->transfer_buffer_length -
|
|
@@ -2300,6 +2335,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
case COMP_STOP_INVAL:
|
|
case COMP_STOP_INVAL:
|
|
xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
|
|
xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
|
|
break;
|
|
break;
|
|
|
|
+ case COMP_STOP_SHORT:
|
|
|
|
+ xhci_dbg(xhci, "Stopped with short packet transfer detected\n");
|
|
|
|
+ break;
|
|
case COMP_STALL:
|
|
case COMP_STALL:
|
|
xhci_dbg(xhci, "Stalled endpoint\n");
|
|
xhci_dbg(xhci, "Stalled endpoint\n");
|
|
ep->ep_state |= EP_HALTED;
|
|
ep->ep_state |= EP_HALTED;
|