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

Commit 22405ed2 authored by Andiry Xu's avatar Andiry Xu Committed by Greg Kroah-Hartman
Browse files

USB xHCI: handle_tx_event() refactor: process_bulk_intr_td



This patch moves the bulk and interrupt td processing part in
handle_tx_event() into a separate function process_bulk_intr_td().

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 8af56be1
Loading
Loading
Loading
Loading
+115 −101
Original line number Diff line number Diff line
@@ -1458,6 +1458,117 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
	return finish_td(xhci, td, event_trb, event, ep, status, false);
}

/*
 * Process bulk and interrupt tds, update urb status and actual_length.
 */
static int process_bulk_intr_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)
{
	struct xhci_ring *ep_ring;
	union xhci_trb *cur_trb;
	struct xhci_segment *cur_seg;
	u32 trb_comp_code;

	ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer);
	trb_comp_code = GET_COMP_CODE(event->transfer_len);

	switch (trb_comp_code) {
	case COMP_SUCCESS:
		/* Double check that the HW transferred everything. */
		if (event_trb != td->last_trb) {
			xhci_warn(xhci, "WARN Successful completion "
					"on short TX\n");
			if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
				*status = -EREMOTEIO;
			else
				*status = 0;
		} else {
			if (usb_endpoint_xfer_bulk(&td->urb->ep->desc))
				xhci_dbg(xhci, "Successful bulk "
						"transfer!\n");
			else
				xhci_dbg(xhci, "Successful interrupt "
						"transfer!\n");
			*status = 0;
		}
		break;
	case COMP_SHORT_TX:
		if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
			*status = -EREMOTEIO;
		else
			*status = 0;
		break;
	default:
		/* Others already handled above */
		break;
	}
	dev_dbg(&td->urb->dev->dev,
			"ep %#x - asked for %d bytes, "
			"%d bytes untransferred\n",
			td->urb->ep->desc.bEndpointAddress,
			td->urb->transfer_buffer_length,
			TRB_LEN(event->transfer_len));
	/* Fast path - was this the last TRB in the TD for this URB? */
	if (event_trb == td->last_trb) {
		if (TRB_LEN(event->transfer_len) != 0) {
			td->urb->actual_length =
				td->urb->transfer_buffer_length -
				TRB_LEN(event->transfer_len);
			if (td->urb->transfer_buffer_length <
					td->urb->actual_length) {
				xhci_warn(xhci, "HC gave bad length "
						"of %d bytes left\n",
						TRB_LEN(event->transfer_len));
				td->urb->actual_length = 0;
				if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
					*status = -EREMOTEIO;
				else
					*status = 0;
			}
			/* Don't overwrite a previously set error code */
			if (*status == -EINPROGRESS) {
				if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
					*status = -EREMOTEIO;
				else
					*status = 0;
			}
		} else {
			td->urb->actual_length =
				td->urb->transfer_buffer_length;
			/* Ignore a short packet completion if the
			 * untransferred length was zero.
			 */
			if (*status == -EREMOTEIO)
				*status = 0;
		}
	} else {
		/* Slow path - walk the list, starting from the dequeue
		 * pointer, to get the actual length transferred.
		 */
		td->urb->actual_length = 0;
		for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
				cur_trb != event_trb;
				next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
			if ((cur_trb->generic.field[3] &
			 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
			    (cur_trb->generic.field[3] &
			 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
				td->urb->actual_length +=
					TRB_LEN(cur_trb->generic.field[2]);
		}
		/* If the ring didn't stop on a Link or No-op TRB, add
		 * in the actual bytes transferred from the Normal TRB
		 */
		if (trb_comp_code != COMP_STOP_INVAL)
			td->urb->actual_length +=
				TRB_LEN(cur_trb->generic.field[2]) -
				TRB_LEN(event->transfer_len);
	}

	return finish_td(xhci, td, event_trb, event, ep, status, false);
}

/*
 * 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.
@@ -1584,109 +1695,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
	}
	/* Now update the urb's actual_length and give back to the core */
	/* Was this a control transfer? */
	if (usb_endpoint_xfer_control(&td->urb->ep->desc)) {
	if (usb_endpoint_xfer_control(&td->urb->ep->desc))
		ret = process_ctrl_td(xhci, td, event_trb, event, ep,
					&status);
		goto cleanup;
	} else {
		switch (trb_comp_code) {
		case COMP_SUCCESS:
			/* Double check that the HW transferred everything. */
			if (event_trb != td->last_trb) {
				xhci_warn(xhci, "WARN Successful completion "
						"on short TX\n");
				if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
					status = -EREMOTEIO;
				else
					status = 0;
			} else {
				if (usb_endpoint_xfer_bulk(&td->urb->ep->desc))
					xhci_dbg(xhci, "Successful bulk "
							"transfer!\n");
				else
					xhci_dbg(xhci, "Successful interrupt "
							"transfer!\n");
				status = 0;
			}
			break;
		case COMP_SHORT_TX:
			if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
				status = -EREMOTEIO;
			else
				status = 0;
			break;
		default:
			/* Others already handled above */
			break;
		}
		dev_dbg(&td->urb->dev->dev,
				"ep %#x - asked for %d bytes, "
				"%d bytes untransferred\n",
				td->urb->ep->desc.bEndpointAddress,
				td->urb->transfer_buffer_length,
				TRB_LEN(event->transfer_len));
		/* Fast path - was this the last TRB in the TD for this URB? */
		if (event_trb == td->last_trb) {
			if (TRB_LEN(event->transfer_len) != 0) {
				td->urb->actual_length =
					td->urb->transfer_buffer_length -
					TRB_LEN(event->transfer_len);
				if (td->urb->transfer_buffer_length <
						td->urb->actual_length) {
					xhci_warn(xhci, "HC gave bad length "
							"of %d bytes left\n",
							TRB_LEN(event->transfer_len));
					td->urb->actual_length = 0;
					if (td->urb->transfer_flags &
							URB_SHORT_NOT_OK)
						status = -EREMOTEIO;
	else
						status = 0;
				}
				/* Don't overwrite a previously set error code */
				if (status == -EINPROGRESS) {
					if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
						status = -EREMOTEIO;
					else
						status = 0;
				}
			} else {
				td->urb->actual_length = td->urb->transfer_buffer_length;
				/* Ignore a short packet completion if the
				 * untransferred length was zero.
				 */
				if (status == -EREMOTEIO)
					status = 0;
			}
		} else {
			/* Slow path - walk the list, starting from the dequeue
			 * pointer, to get the actual length transferred.
			 */
			union xhci_trb *cur_trb;
			struct xhci_segment *cur_seg;

			td->urb->actual_length = 0;
			for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
					cur_trb != event_trb;
					next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
				if ((cur_trb->generic.field[3] &
				 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
				    (cur_trb->generic.field[3] &
				 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
					td->urb->actual_length +=
						TRB_LEN(cur_trb->generic.field[2]);
			}
			/* If the ring didn't stop on a Link or No-op TRB, add
			 * in the actual bytes transferred from the Normal TRB
			 */
			if (trb_comp_code != COMP_STOP_INVAL)
				td->urb->actual_length +=
					TRB_LEN(cur_trb->generic.field[2]) -
					TRB_LEN(event->transfer_len);
		}
	}

	ret =  finish_td(xhci, td, event_trb, event, ep, &status, false);
		ret = process_bulk_intr_td(xhci, td, event_trb, event, ep,
					&status);

cleanup:
	inc_deq(xhci, xhci->event_ring, true);