Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4422da61 authored by Andiry Xu's avatar Andiry Xu Committed by Greg Kroah-Hartman
Browse files

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: default avatarAndiry Xu <andiry.xu@amd.com>
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b972302b
Loading
Loading
Loading
Loading
+112 −73
Original line number Diff line number Diff line
@@ -1257,6 +1257,104 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
	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
 * 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;
	struct xhci_ep_ctx *ep_ctx;
	u32 trb_comp_code;
	int ret = 0;

	xhci_dbg(xhci, "In %s\n", __func__);
	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",
				(unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
		xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
		urb = NULL;
		goto cleanup;
	}
	xhci_dbg(xhci, "%s - getting list entry\n", __func__);
@@ -1379,7 +1477,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
			break;
		}
		xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n");
		urb = NULL;
		goto cleanup;
	}
	/* 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,
					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
@@ -1456,7 +1556,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
						td->urb->transfer_buffer_length -
						TRB_LEN(event->transfer_len);
					xhci_dbg(xhci, "Waiting for status stage event\n");
					urb = NULL;
					goto cleanup;
				}
			}
@@ -1558,68 +1657,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
					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:
		/* 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 =  finish_td(xhci, td, event_trb, event, ep, &status, false);

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;
		/* Leave the TD around for the reset endpoint function to use
		 * (but only if it's not a control endpoint, since we already
		 * queued the Set TR dequeue pointer command for stalled
@@ -1627,17 +1674,9 @@ td_cleanup:
		 */
		if (usb_endpoint_xfer_control(&urb->ep->desc) ||
			(trb_comp_code != COMP_STALL &&
				trb_comp_code != COMP_BABBLE)) {
				trb_comp_code != COMP_BABBLE))
			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);
		xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
				urb, urb->actual_length, status);