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

Commit 09c352ed authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman
Browse files

xhci: cleanup isoc tranfers queuing code



Clean up xhci_queue_isoc_tx() and helpers to prepare them for USB 3.1 and
xhci 1.1 isoc TRB changes.

Only functional change is adding xhci version 1.1 to the BEI flag check
toghether with xhci version 1.0. Both versions behave the same.

Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8ef8a9f5
Loading
Loading
Loading
Loading
+53 −72
Original line number Original line Diff line number Diff line
@@ -3558,12 +3558,11 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
 * zero.  Only xHCI 1.0 host controllers support this field.
 * zero.  Only xHCI 1.0 host controllers support this field.
 */
 */
static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
		struct usb_device *udev,
		struct urb *urb, unsigned int total_packet_count)
		struct urb *urb, unsigned int total_packet_count)
{
{
	unsigned int max_burst;
	unsigned int max_burst;


	if (xhci->hci_version < 0x100 || udev->speed < USB_SPEED_SUPER)
	if (xhci->hci_version < 0x100 || urb->dev->speed < USB_SPEED_SUPER)
		return 0;
		return 0;


	max_burst = urb->ep->ss_ep_comp.bMaxBurst;
	max_burst = urb->ep->ss_ep_comp.bMaxBurst;
@@ -3579,7 +3578,6 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,
 * contain 1 to (bMaxBurst + 1) packets.
 * contain 1 to (bMaxBurst + 1) packets.
 */
 */
static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
		struct usb_device *udev,
		struct urb *urb, unsigned int total_packet_count)
		struct urb *urb, unsigned int total_packet_count)
{
{
	unsigned int max_burst;
	unsigned int max_burst;
@@ -3588,9 +3586,7 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
	if (xhci->hci_version < 0x100)
	if (xhci->hci_version < 0x100)
		return 0;
		return 0;


	switch (udev->speed) {
	if (urb->dev->speed >= USB_SPEED_SUPER) {
	case USB_SPEED_SUPER_PLUS:
	case USB_SPEED_SUPER:
		/* bMaxBurst is zero based: 0 means 1 packet per burst */
		/* bMaxBurst is zero based: 0 means 1 packet per burst */
		max_burst = urb->ep->ss_ep_comp.bMaxBurst;
		max_burst = urb->ep->ss_ep_comp.bMaxBurst;
		residue = total_packet_count % (max_burst + 1);
		residue = total_packet_count % (max_burst + 1);
@@ -3600,12 +3596,11 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci,
		if (residue == 0)
		if (residue == 0)
			return max_burst;
			return max_burst;
		return residue - 1;
		return residue - 1;
	default:
	}
	if (total_packet_count == 0)
	if (total_packet_count == 0)
		return 0;
		return 0;
	return total_packet_count - 1;
	return total_packet_count - 1;
}
}
}


/*
/*
 * Calculates Frame ID field of the isochronous TRB identifies the
 * Calculates Frame ID field of the isochronous TRB identifies the
@@ -3715,6 +3710,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
	int i, j;
	int i, j;
	bool more_trbs_coming;
	bool more_trbs_coming;
	struct xhci_virt_ep *xep;
	struct xhci_virt_ep *xep;
	int frame_id;


	xep = &xhci->devs[slot_id]->eps[ep_index];
	xep = &xhci->devs[slot_id]->eps[ep_index];
	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
@@ -3724,33 +3720,31 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
		xhci_dbg(xhci, "Isoc URB with zero packets?\n");
		xhci_dbg(xhci, "Isoc URB with zero packets?\n");
		return -EINVAL;
		return -EINVAL;
	}
	}

	start_addr = (u64) urb->transfer_dma;
	start_addr = (u64) urb->transfer_dma;
	start_trb = &ep_ring->enqueue->generic;
	start_trb = &ep_ring->enqueue->generic;
	start_cycle = ep_ring->cycle_state;
	start_cycle = ep_ring->cycle_state;


	urb_priv = urb->hcpriv;
	urb_priv = urb->hcpriv;
	/* Queue the first TRB, even if it's zero-length */
	/* Queue the TRBs for each TD, even if they are zero-length */
	for (i = 0; i < num_tds; i++) {
	for (i = 0; i < num_tds; i++) {
		unsigned int total_packet_count;
		unsigned int total_pkt_count, max_pkt;
		unsigned int burst_count;
		unsigned int burst_count, last_burst_pkt_count;
		unsigned int residue;
		u32 sia_frame_id;


		first_trb = true;
		first_trb = true;
		running_total = 0;
		running_total = 0;
		addr = start_addr + urb->iso_frame_desc[i].offset;
		addr = start_addr + urb->iso_frame_desc[i].offset;
		td_len = urb->iso_frame_desc[i].length;
		td_len = urb->iso_frame_desc[i].length;
		td_remain_len = td_len;
		td_remain_len = td_len;
		total_packet_count = DIV_ROUND_UP(td_len,
		max_pkt = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
				GET_MAX_PACKET(
		total_pkt_count = DIV_ROUND_UP(td_len, max_pkt);
					usb_endpoint_maxp(&urb->ep->desc)));

		/* A zero-length transfer still involves at least one packet. */
		/* A zero-length transfer still involves at least one packet. */
		if (total_packet_count == 0)
		if (total_pkt_count == 0)
			total_packet_count++;
			total_pkt_count++;
		burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
		burst_count = xhci_get_burst_count(xhci, urb, total_pkt_count);
				total_packet_count);
		last_burst_pkt_count = xhci_get_last_burst_packet_count(xhci,
		residue = xhci_get_last_burst_packet_count(xhci,
							urb, total_pkt_count);
				urb->dev, urb, total_packet_count);


		trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
		trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);


@@ -3761,68 +3755,55 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
				return ret;
				return ret;
			goto cleanup;
			goto cleanup;
		}
		}

		td = urb_priv->td[i];
		td = urb_priv->td[i];
		for (j = 0; j < trbs_per_td; j++) {
			int frame_id = 0;
			u32 remainder = 0;
			field = 0;

			if (first_trb) {
				field = TRB_TBC(burst_count) |
					TRB_TLBPC(residue);
				/* Queue the isoc TRB */
				field |= TRB_TYPE(TRB_ISOC);


				/* Calculate Frame ID and SIA fields */
		/* use SIA as default, if frame id is used overwrite it */
		sia_frame_id = TRB_SIA;
		if (!(urb->transfer_flags & URB_ISO_ASAP) &&
		if (!(urb->transfer_flags & URB_ISO_ASAP) &&
		    HCC_CFC(xhci->hcc_params)) {
		    HCC_CFC(xhci->hcc_params)) {
					frame_id = xhci_get_isoc_frame_id(xhci,
			frame_id = xhci_get_isoc_frame_id(xhci, urb, i);
									  urb,
									  i);
			if (frame_id >= 0)
			if (frame_id >= 0)
						field |= TRB_FRAME_ID(frame_id);
				sia_frame_id = TRB_FRAME_ID(frame_id);
					else
		}
						field |= TRB_SIA;
		/*
				} else
		 * Set isoc specific data for the first TRB in a TD.
					field |= TRB_SIA;
		 * Prevent HW from getting the TRBs by keeping the cycle state
		 * inverted in the first TDs isoc TRB.
		 */
		field = TRB_TBC(burst_count) |
			TRB_TYPE(TRB_ISOC) |
			TRB_TLBPC(last_burst_pkt_count) |
			sia_frame_id |
			(i ? ep_ring->cycle_state : !start_cycle);


				if (i == 0) {
		/* fill the rest of the TRB fields, and remaining normal TRBs */
					if (start_cycle == 0)
		for (j = 0; j < trbs_per_td; j++) {
						field |= 0x1;
			u32 remainder = 0;
				} else

					field |= ep_ring->cycle_state;
			/* only first TRB is isoc, overwrite otherwise */
			if (!first_trb)
				field = TRB_TYPE(TRB_NORMAL) |
					ep_ring->cycle_state;
			first_trb = false;
			first_trb = false;
			} else {
				/* Queue other normal TRBs */
				field |= TRB_TYPE(TRB_NORMAL);
				field |= ep_ring->cycle_state;
			}


			/* Only set interrupt on short packet for IN EPs */
			/* Only set interrupt on short packet for IN EPs */
			if (usb_urb_dir_in(urb))
			if (usb_urb_dir_in(urb))
				field |= TRB_ISP;
				field |= TRB_ISP;


			/* Chain all the TRBs together; clear the chain bit in
			/* Set the chain bit for all except the last TRB  */
			 * the last TRB to indicate it's the last TRB in the
			 * chain.
			 */
			if (j < trbs_per_td - 1) {
			if (j < trbs_per_td - 1) {
				field |= TRB_CHAIN;
				more_trbs_coming = true;
				more_trbs_coming = true;
				field |= TRB_CHAIN;
			} else {
			} else {
				more_trbs_coming = false;
				td->last_trb = ep_ring->enqueue;
				td->last_trb = ep_ring->enqueue;
				field |= TRB_IOC;
				field |= TRB_IOC;
				if (xhci->hci_version == 0x100 &&
				/* set BEI, except for the last TD */
						!(xhci->quirks &
				if (xhci->hci_version >= 0x100 &&
							XHCI_AVOID_BEI)) {
				    !(xhci->quirks & XHCI_AVOID_BEI) &&
					/* Set BEI bit except for the last td */
				    i < num_tds - 1)
					if (i < num_tds - 1)
					field |= TRB_BEI;
					field |= TRB_BEI;
			}
			}
				more_trbs_coming = false;
			}

			/* Calculate TRB length */
			/* Calculate TRB length */
			trb_buff_len = TRB_MAX_BUFF_SIZE -
			trb_buff_len = TRB_MAX_BUFF_SIZE -
				(addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
				(addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));