USB: xHCI: handle_tx_event() refactor: finish_td
This patch moves the td universal processing part in handle_tx_event() into a separate function finish_td(). if finish_td() returns 1, it indicates the urb can be given back. Signed-off-by: Andiry Xu <andiry.xu@amd.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
b972302b0a
commit
4422da6155
|
@ -1257,6 +1257,104 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finish the td processing, remove the td from td list;
|
||||||
|
* Return 1 if the urb can be given back.
|
||||||
|
*/
|
||||||
|
static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
|
union xhci_trb *event_trb, struct xhci_transfer_event *event,
|
||||||
|
struct xhci_virt_ep *ep, int *status, bool skip)
|
||||||
|
{
|
||||||
|
struct xhci_virt_device *xdev;
|
||||||
|
struct xhci_ring *ep_ring;
|
||||||
|
unsigned int slot_id;
|
||||||
|
int ep_index;
|
||||||
|
struct urb *urb = NULL;
|
||||||
|
struct xhci_ep_ctx *ep_ctx;
|
||||||
|
int ret = 0;
|
||||||
|
u32 trb_comp_code;
|
||||||
|
|
||||||
|
slot_id = TRB_TO_SLOT_ID(event->flags);
|
||||||
|
xdev = xhci->devs[slot_id];
|
||||||
|
ep_index = TRB_TO_EP_ID(event->flags) - 1;
|
||||||
|
ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
|
||||||
|
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
|
||||||
|
trb_comp_code = GET_COMP_CODE(event->transfer_len);
|
||||||
|
|
||||||
|
if (skip)
|
||||||
|
goto td_cleanup;
|
||||||
|
|
||||||
|
if (trb_comp_code == COMP_STOP_INVAL ||
|
||||||
|
trb_comp_code == COMP_STOP) {
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
ep->stopped_td = td;
|
||||||
|
ep->stopped_trb = event_trb;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (trb_comp_code == COMP_STALL) {
|
||||||
|
/* The transfer is completed from the driver's
|
||||||
|
* perspective, but we need to issue a set dequeue
|
||||||
|
* command for this stalled endpoint to move the dequeue
|
||||||
|
* pointer past the TD. We can't do that here because
|
||||||
|
* the halt condition must be cleared first. Let the
|
||||||
|
* USB class driver clear the stall later.
|
||||||
|
*/
|
||||||
|
ep->stopped_td = td;
|
||||||
|
ep->stopped_trb = event_trb;
|
||||||
|
ep->stopped_stream = ep_ring->stream_id;
|
||||||
|
} else if (xhci_requires_manual_halt_cleanup(xhci,
|
||||||
|
ep_ctx, trb_comp_code)) {
|
||||||
|
/* Other types of errors halt the endpoint, but the
|
||||||
|
* class driver doesn't call usb_reset_endpoint() unless
|
||||||
|
* the error is -EPIPE. Clear the halted status in the
|
||||||
|
* xHCI hardware manually.
|
||||||
|
*/
|
||||||
|
xhci_cleanup_halted_endpoint(xhci,
|
||||||
|
slot_id, ep_index, ep_ring->stream_id,
|
||||||
|
td, event_trb);
|
||||||
|
} else {
|
||||||
|
/* Update ring dequeue pointer */
|
||||||
|
while (ep_ring->dequeue != td->last_trb)
|
||||||
|
inc_deq(xhci, ep_ring, false);
|
||||||
|
inc_deq(xhci, ep_ring, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
td_cleanup:
|
||||||
|
/* Clean up the endpoint's TD list */
|
||||||
|
urb = td->urb;
|
||||||
|
|
||||||
|
/* Do one last check of the actual transfer length.
|
||||||
|
* If the host controller said we transferred more data than
|
||||||
|
* the buffer length, urb->actual_length will be a very big
|
||||||
|
* number (since it's unsigned). Play it safe and say we didn't
|
||||||
|
* transfer anything.
|
||||||
|
*/
|
||||||
|
if (urb->actual_length > urb->transfer_buffer_length) {
|
||||||
|
xhci_warn(xhci, "URB transfer length is wrong, "
|
||||||
|
"xHC issue? req. len = %u, "
|
||||||
|
"act. len = %u\n",
|
||||||
|
urb->transfer_buffer_length,
|
||||||
|
urb->actual_length);
|
||||||
|
urb->actual_length = 0;
|
||||||
|
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
||||||
|
*status = -EREMOTEIO;
|
||||||
|
else
|
||||||
|
*status = 0;
|
||||||
|
}
|
||||||
|
list_del(&td->td_list);
|
||||||
|
/* Was this TD slated to be cancelled but completed anyway? */
|
||||||
|
if (!list_empty(&td->cancelled_td_list))
|
||||||
|
list_del(&td->cancelled_td_list);
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this function returns an error condition, it means it got a Transfer
|
* If this function returns an error condition, it means it got a Transfer
|
||||||
* event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
|
* event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
|
||||||
|
@ -1278,6 +1376,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
int status = -EINPROGRESS;
|
int status = -EINPROGRESS;
|
||||||
struct xhci_ep_ctx *ep_ctx;
|
struct xhci_ep_ctx *ep_ctx;
|
||||||
u32 trb_comp_code;
|
u32 trb_comp_code;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
xhci_dbg(xhci, "In %s\n", __func__);
|
xhci_dbg(xhci, "In %s\n", __func__);
|
||||||
slot_id = TRB_TO_SLOT_ID(event->flags);
|
slot_id = TRB_TO_SLOT_ID(event->flags);
|
||||||
|
@ -1308,7 +1407,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
|
xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
|
||||||
(unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
|
(unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
|
||||||
xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
|
xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
|
||||||
urb = NULL;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
xhci_dbg(xhci, "%s - getting list entry\n", __func__);
|
xhci_dbg(xhci, "%s - getting list entry\n", __func__);
|
||||||
|
@ -1379,7 +1477,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n");
|
xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n");
|
||||||
urb = NULL;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
/* Now update the urb's actual_length and give back to the core */
|
/* Now update the urb's actual_length and give back to the core */
|
||||||
|
@ -1427,7 +1524,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
|
|
||||||
xhci_cleanup_halted_endpoint(xhci,
|
xhci_cleanup_halted_endpoint(xhci,
|
||||||
slot_id, ep_index, 0, td, event_trb);
|
slot_id, ep_index, 0, td, event_trb);
|
||||||
goto td_cleanup;
|
|
||||||
|
ret = finish_td(xhci, td, event_trb, event, ep,
|
||||||
|
&status, true);
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Did we transfer any data, despite the errors that might have
|
* Did we transfer any data, despite the errors that might have
|
||||||
|
@ -1456,7 +1556,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
td->urb->transfer_buffer_length -
|
td->urb->transfer_buffer_length -
|
||||||
TRB_LEN(event->transfer_len);
|
TRB_LEN(event->transfer_len);
|
||||||
xhci_dbg(xhci, "Waiting for status stage event\n");
|
xhci_dbg(xhci, "Waiting for status stage event\n");
|
||||||
urb = NULL;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1558,68 +1657,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
||||||
TRB_LEN(event->transfer_len);
|
TRB_LEN(event->transfer_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (trb_comp_code == COMP_STOP_INVAL ||
|
|
||||||
trb_comp_code == COMP_STOP) {
|
|
||||||
/* 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.
|
|
||||||
*/
|
|
||||||
ep->stopped_td = td;
|
|
||||||
ep->stopped_trb = event_trb;
|
|
||||||
} else {
|
|
||||||
if (trb_comp_code == COMP_STALL) {
|
|
||||||
/* The transfer is completed from the driver's
|
|
||||||
* perspective, but we need to issue a set dequeue
|
|
||||||
* command for this stalled endpoint to move the dequeue
|
|
||||||
* pointer past the TD. We can't do that here because
|
|
||||||
* the halt condition must be cleared first. Let the
|
|
||||||
* USB class driver clear the stall later.
|
|
||||||
*/
|
|
||||||
ep->stopped_td = td;
|
|
||||||
ep->stopped_trb = event_trb;
|
|
||||||
ep->stopped_stream = ep_ring->stream_id;
|
|
||||||
} else if (xhci_requires_manual_halt_cleanup(xhci,
|
|
||||||
ep_ctx, trb_comp_code)) {
|
|
||||||
/* Other types of errors halt the endpoint, but the
|
|
||||||
* class driver doesn't call usb_reset_endpoint() unless
|
|
||||||
* the error is -EPIPE. Clear the halted status in the
|
|
||||||
* xHCI hardware manually.
|
|
||||||
*/
|
|
||||||
xhci_cleanup_halted_endpoint(xhci,
|
|
||||||
slot_id, ep_index, ep_ring->stream_id, td, event_trb);
|
|
||||||
} else {
|
|
||||||
/* Update ring dequeue pointer */
|
|
||||||
while (ep_ring->dequeue != td->last_trb)
|
|
||||||
inc_deq(xhci, ep_ring, false);
|
|
||||||
inc_deq(xhci, ep_ring, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
td_cleanup:
|
ret = finish_td(xhci, td, event_trb, event, ep, &status, false);
|
||||||
/* Clean up the endpoint's TD list */
|
|
||||||
|
cleanup:
|
||||||
|
inc_deq(xhci, xhci->event_ring, true);
|
||||||
|
xhci_set_hc_event_deq(xhci);
|
||||||
|
|
||||||
|
/* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
|
||||||
|
if (ret) {
|
||||||
urb = td->urb;
|
urb = td->urb;
|
||||||
/* Do one last check of the actual transfer length.
|
|
||||||
* If the host controller said we transferred more data than
|
|
||||||
* the buffer length, urb->actual_length will be a very big
|
|
||||||
* number (since it's unsigned). Play it safe and say we didn't
|
|
||||||
* transfer anything.
|
|
||||||
*/
|
|
||||||
if (urb->actual_length > urb->transfer_buffer_length) {
|
|
||||||
xhci_warn(xhci, "URB transfer length is wrong, "
|
|
||||||
"xHC issue? req. len = %u, "
|
|
||||||
"act. len = %u\n",
|
|
||||||
urb->transfer_buffer_length,
|
|
||||||
urb->actual_length);
|
|
||||||
urb->actual_length = 0;
|
|
||||||
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
|
||||||
status = -EREMOTEIO;
|
|
||||||
else
|
|
||||||
status = 0;
|
|
||||||
}
|
|
||||||
list_del(&td->td_list);
|
|
||||||
/* Was this TD slated to be cancelled but completed anyway? */
|
|
||||||
if (!list_empty(&td->cancelled_td_list))
|
|
||||||
list_del(&td->cancelled_td_list);
|
|
||||||
|
|
||||||
/* Leave the TD around for the reset endpoint function to use
|
/* Leave the TD around for the reset endpoint function to use
|
||||||
* (but only if it's not a control endpoint, since we already
|
* (but only if it's not a control endpoint, since we already
|
||||||
* queued the Set TR dequeue pointer command for stalled
|
* queued the Set TR dequeue pointer command for stalled
|
||||||
|
@ -1627,17 +1674,9 @@ td_cleanup:
|
||||||
*/
|
*/
|
||||||
if (usb_endpoint_xfer_control(&urb->ep->desc) ||
|
if (usb_endpoint_xfer_control(&urb->ep->desc) ||
|
||||||
(trb_comp_code != COMP_STALL &&
|
(trb_comp_code != COMP_STALL &&
|
||||||
trb_comp_code != COMP_BABBLE)) {
|
trb_comp_code != COMP_BABBLE))
|
||||||
kfree(td);
|
kfree(td);
|
||||||
}
|
|
||||||
urb->hcpriv = NULL;
|
|
||||||
}
|
|
||||||
cleanup:
|
|
||||||
inc_deq(xhci, xhci->event_ring, true);
|
|
||||||
xhci_set_hc_event_deq(xhci);
|
|
||||||
|
|
||||||
/* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
|
|
||||||
if (urb) {
|
|
||||||
usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
|
usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
|
||||||
xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
|
xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
|
||||||
urb, urb->actual_length, status);
|
urb, urb->actual_length, status);
|
||||||
|
|
Loading…
Reference in New Issue