162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cadence CDNSP DRD Driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020 Cadence.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Pawel Laszczak <pawell@cadence.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Code based on Linux XHCI driver.
1062306a36Sopenharmony_ci * Origin: Copyright (C) 2008 Intel Corp
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * Ring initialization rules:
1562306a36Sopenharmony_ci * 1. Each segment is initialized to zero, except for link TRBs.
1662306a36Sopenharmony_ci * 2. Ring cycle state = 0. This represents Producer Cycle State (PCS) or
1762306a36Sopenharmony_ci *    Consumer Cycle State (CCS), depending on ring function.
1862306a36Sopenharmony_ci * 3. Enqueue pointer = dequeue pointer = address of first TRB in the segment.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Ring behavior rules:
2162306a36Sopenharmony_ci * 1. A ring is empty if enqueue == dequeue. This means there will always be at
2262306a36Sopenharmony_ci *    least one free TRB in the ring. This is useful if you want to turn that
2362306a36Sopenharmony_ci *    into a link TRB and expand the ring.
2462306a36Sopenharmony_ci * 2. When incrementing an enqueue or dequeue pointer, if the next TRB is a
2562306a36Sopenharmony_ci *    link TRB, then load the pointer with the address in the link TRB. If the
2662306a36Sopenharmony_ci *    link TRB had its toggle bit set, you may need to update the ring cycle
2762306a36Sopenharmony_ci *    state (see cycle bit rules). You may have to do this multiple times
2862306a36Sopenharmony_ci *    until you reach a non-link TRB.
2962306a36Sopenharmony_ci * 3. A ring is full if enqueue++ (for the definition of increment above)
3062306a36Sopenharmony_ci *    equals the dequeue pointer.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * Cycle bit rules:
3362306a36Sopenharmony_ci * 1. When a consumer increments a dequeue pointer and encounters a toggle bit
3462306a36Sopenharmony_ci *    in a link TRB, it must toggle the ring cycle state.
3562306a36Sopenharmony_ci * 2. When a producer increments an enqueue pointer and encounters a toggle bit
3662306a36Sopenharmony_ci *    in a link TRB, it must toggle the ring cycle state.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Producer rules:
3962306a36Sopenharmony_ci * 1. Check if ring is full before you enqueue.
4062306a36Sopenharmony_ci * 2. Write the ring cycle state to the cycle bit in the TRB you're enqueuing.
4162306a36Sopenharmony_ci *    Update enqueue pointer between each write (which may update the ring
4262306a36Sopenharmony_ci *    cycle state).
4362306a36Sopenharmony_ci * 3. Notify consumer. If SW is producer, it rings the doorbell for command
4462306a36Sopenharmony_ci *    and endpoint rings. If controller is the producer for the event ring,
4562306a36Sopenharmony_ci *    and it generates an interrupt according to interrupt modulation rules.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * Consumer rules:
4862306a36Sopenharmony_ci * 1. Check if TRB belongs to you. If the cycle bit == your ring cycle state,
4962306a36Sopenharmony_ci *    the TRB is owned by the consumer.
5062306a36Sopenharmony_ci * 2. Update dequeue pointer (which may update the ring cycle state) and
5162306a36Sopenharmony_ci *    continue processing TRBs until you reach a TRB which is not owned by you.
5262306a36Sopenharmony_ci * 3. Notify the producer. SW is the consumer for the event ring, and it
5362306a36Sopenharmony_ci *    updates event ring dequeue pointer. Controller is the consumer for the
5462306a36Sopenharmony_ci *    command and endpoint rings; it generates events on the event ring
5562306a36Sopenharmony_ci *    for these.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#include <linux/scatterlist.h>
5962306a36Sopenharmony_ci#include <linux/dma-mapping.h>
6062306a36Sopenharmony_ci#include <linux/delay.h>
6162306a36Sopenharmony_ci#include <linux/slab.h>
6262306a36Sopenharmony_ci#include <linux/irq.h>
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#include "cdnsp-trace.h"
6562306a36Sopenharmony_ci#include "cdnsp-gadget.h"
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/*
6862306a36Sopenharmony_ci * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
6962306a36Sopenharmony_ci * address of the TRB.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cidma_addr_t cdnsp_trb_virt_to_dma(struct cdnsp_segment *seg,
7262306a36Sopenharmony_ci				 union cdnsp_trb *trb)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	unsigned long segment_offset = trb - seg->trbs;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (trb < seg->trbs || segment_offset >= TRBS_PER_SEGMENT)
7762306a36Sopenharmony_ci		return 0;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return seg->dma + (segment_offset * sizeof(*trb));
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic bool cdnsp_trb_is_noop(union cdnsp_trb *trb)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	return TRB_TYPE_NOOP_LE32(trb->generic.field[3]);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic bool cdnsp_trb_is_link(union cdnsp_trb *trb)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	return TRB_TYPE_LINK_LE32(trb->link.control);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cibool cdnsp_last_trb_on_seg(struct cdnsp_segment *seg, union cdnsp_trb *trb)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	return trb == &seg->trbs[TRBS_PER_SEGMENT - 1];
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cibool cdnsp_last_trb_on_ring(struct cdnsp_ring *ring,
9862306a36Sopenharmony_ci			    struct cdnsp_segment *seg,
9962306a36Sopenharmony_ci			    union cdnsp_trb *trb)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	return cdnsp_last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic bool cdnsp_link_trb_toggles_cycle(union cdnsp_trb *trb)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic void cdnsp_trb_to_noop(union cdnsp_trb *trb, u32 noop_type)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	if (cdnsp_trb_is_link(trb)) {
11262306a36Sopenharmony_ci		/* Unchain chained link TRBs. */
11362306a36Sopenharmony_ci		trb->link.control &= cpu_to_le32(~TRB_CHAIN);
11462306a36Sopenharmony_ci	} else {
11562306a36Sopenharmony_ci		trb->generic.field[0] = 0;
11662306a36Sopenharmony_ci		trb->generic.field[1] = 0;
11762306a36Sopenharmony_ci		trb->generic.field[2] = 0;
11862306a36Sopenharmony_ci		/* Preserve only the cycle bit of this TRB. */
11962306a36Sopenharmony_ci		trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
12062306a36Sopenharmony_ci		trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(noop_type));
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * Updates trb to point to the next TRB in the ring, and updates seg if the next
12662306a36Sopenharmony_ci * TRB is in a new segment. This does not skip over link TRBs, and it does not
12762306a36Sopenharmony_ci * effect the ring dequeue or enqueue pointers.
12862306a36Sopenharmony_ci */
12962306a36Sopenharmony_cistatic void cdnsp_next_trb(struct cdnsp_device *pdev,
13062306a36Sopenharmony_ci			   struct cdnsp_ring *ring,
13162306a36Sopenharmony_ci			   struct cdnsp_segment **seg,
13262306a36Sopenharmony_ci			   union cdnsp_trb **trb)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	if (cdnsp_trb_is_link(*trb)) {
13562306a36Sopenharmony_ci		*seg = (*seg)->next;
13662306a36Sopenharmony_ci		*trb = ((*seg)->trbs);
13762306a36Sopenharmony_ci	} else {
13862306a36Sopenharmony_ci		(*trb)++;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/*
14362306a36Sopenharmony_ci * See Cycle bit rules. SW is the consumer for the event ring only.
14462306a36Sopenharmony_ci * Don't make a ring full of link TRBs. That would be dumb and this would loop.
14562306a36Sopenharmony_ci */
14662306a36Sopenharmony_civoid cdnsp_inc_deq(struct cdnsp_device *pdev, struct cdnsp_ring *ring)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	/* event ring doesn't have link trbs, check for last trb. */
14962306a36Sopenharmony_ci	if (ring->type == TYPE_EVENT) {
15062306a36Sopenharmony_ci		if (!cdnsp_last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
15162306a36Sopenharmony_ci			ring->dequeue++;
15262306a36Sopenharmony_ci			goto out;
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		if (cdnsp_last_trb_on_ring(ring, ring->deq_seg, ring->dequeue))
15662306a36Sopenharmony_ci			ring->cycle_state ^= 1;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		ring->deq_seg = ring->deq_seg->next;
15962306a36Sopenharmony_ci		ring->dequeue = ring->deq_seg->trbs;
16062306a36Sopenharmony_ci		goto out;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* All other rings have link trbs. */
16462306a36Sopenharmony_ci	if (!cdnsp_trb_is_link(ring->dequeue)) {
16562306a36Sopenharmony_ci		ring->dequeue++;
16662306a36Sopenharmony_ci		ring->num_trbs_free++;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	while (cdnsp_trb_is_link(ring->dequeue)) {
16962306a36Sopenharmony_ci		ring->deq_seg = ring->deq_seg->next;
17062306a36Sopenharmony_ci		ring->dequeue = ring->deq_seg->trbs;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ciout:
17362306a36Sopenharmony_ci	trace_cdnsp_inc_deq(ring);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/*
17762306a36Sopenharmony_ci * See Cycle bit rules. SW is the consumer for the event ring only.
17862306a36Sopenharmony_ci * Don't make a ring full of link TRBs. That would be dumb and this would loop.
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * If we've just enqueued a TRB that is in the middle of a TD (meaning the
18162306a36Sopenharmony_ci * chain bit is set), then set the chain bit in all the following link TRBs.
18262306a36Sopenharmony_ci * If we've enqueued the last TRB in a TD, make sure the following link TRBs
18362306a36Sopenharmony_ci * have their chain bit cleared (so that each Link TRB is a separate TD).
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci * @more_trbs_coming:	Will you enqueue more TRBs before ringing the doorbell.
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_cistatic void cdnsp_inc_enq(struct cdnsp_device *pdev,
18862306a36Sopenharmony_ci			  struct cdnsp_ring *ring,
18962306a36Sopenharmony_ci			  bool more_trbs_coming)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	union cdnsp_trb *next;
19262306a36Sopenharmony_ci	u32 chain;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* If this is not event ring, there is one less usable TRB. */
19762306a36Sopenharmony_ci	if (!cdnsp_trb_is_link(ring->enqueue))
19862306a36Sopenharmony_ci		ring->num_trbs_free--;
19962306a36Sopenharmony_ci	next = ++(ring->enqueue);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Update the dequeue pointer further if that was a link TRB */
20262306a36Sopenharmony_ci	while (cdnsp_trb_is_link(next)) {
20362306a36Sopenharmony_ci		/*
20462306a36Sopenharmony_ci		 * If the caller doesn't plan on enqueuing more TDs before
20562306a36Sopenharmony_ci		 * ringing the doorbell, then we don't want to give the link TRB
20662306a36Sopenharmony_ci		 * to the hardware just yet. We'll give the link TRB back in
20762306a36Sopenharmony_ci		 * cdnsp_prepare_ring() just before we enqueue the TD at the
20862306a36Sopenharmony_ci		 * top of the ring.
20962306a36Sopenharmony_ci		 */
21062306a36Sopenharmony_ci		if (!chain && !more_trbs_coming)
21162306a36Sopenharmony_ci			break;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		next->link.control &= cpu_to_le32(~TRB_CHAIN);
21462306a36Sopenharmony_ci		next->link.control |= cpu_to_le32(chain);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		/* Give this link TRB to the hardware */
21762306a36Sopenharmony_ci		wmb();
21862306a36Sopenharmony_ci		next->link.control ^= cpu_to_le32(TRB_CYCLE);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		/* Toggle the cycle bit after the last ring segment. */
22162306a36Sopenharmony_ci		if (cdnsp_link_trb_toggles_cycle(next))
22262306a36Sopenharmony_ci			ring->cycle_state ^= 1;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci		ring->enq_seg = ring->enq_seg->next;
22562306a36Sopenharmony_ci		ring->enqueue = ring->enq_seg->trbs;
22662306a36Sopenharmony_ci		next = ring->enqueue;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	trace_cdnsp_inc_enq(ring);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/*
23362306a36Sopenharmony_ci * Check to see if there's room to enqueue num_trbs on the ring and make sure
23462306a36Sopenharmony_ci * enqueue pointer will not advance into dequeue segment.
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_cistatic bool cdnsp_room_on_ring(struct cdnsp_device *pdev,
23762306a36Sopenharmony_ci			       struct cdnsp_ring *ring,
23862306a36Sopenharmony_ci			       unsigned int num_trbs)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	int num_trbs_in_deq_seg;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (ring->num_trbs_free < num_trbs)
24362306a36Sopenharmony_ci		return false;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
24662306a36Sopenharmony_ci		num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg)
24962306a36Sopenharmony_ci			return false;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return true;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * Workaround for L1: controller has issue with resuming from L1 after
25762306a36Sopenharmony_ci * setting doorbell for endpoint during L1 state. This function forces
25862306a36Sopenharmony_ci * resume signal in such case.
25962306a36Sopenharmony_ci */
26062306a36Sopenharmony_cistatic void cdnsp_force_l0_go(struct cdnsp_device *pdev)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	if (pdev->active_port == &pdev->usb2_port && pdev->gadget.lpm_capable)
26362306a36Sopenharmony_ci		cdnsp_set_link_state(pdev, &pdev->active_port->regs->portsc, XDEV_U0);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci/* Ring the doorbell after placing a command on the ring. */
26762306a36Sopenharmony_civoid cdnsp_ring_cmd_db(struct cdnsp_device *pdev)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	writel(DB_VALUE_CMD, &pdev->dba->cmd_db);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/*
27362306a36Sopenharmony_ci * Ring the doorbell after placing a transfer on the ring.
27462306a36Sopenharmony_ci * Returns true if doorbell was set, otherwise false.
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_cistatic bool cdnsp_ring_ep_doorbell(struct cdnsp_device *pdev,
27762306a36Sopenharmony_ci				   struct cdnsp_ep *pep,
27862306a36Sopenharmony_ci				   unsigned int stream_id)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	__le32 __iomem *reg_addr = &pdev->dba->ep_db;
28162306a36Sopenharmony_ci	unsigned int ep_state = pep->ep_state;
28262306a36Sopenharmony_ci	unsigned int db_value;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/*
28562306a36Sopenharmony_ci	 * Don't ring the doorbell for this endpoint if endpoint is halted or
28662306a36Sopenharmony_ci	 * disabled.
28762306a36Sopenharmony_ci	 */
28862306a36Sopenharmony_ci	if (ep_state & EP_HALTED || !(ep_state & EP_ENABLED))
28962306a36Sopenharmony_ci		return false;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* For stream capable endpoints driver can ring doorbell only twice. */
29262306a36Sopenharmony_ci	if (pep->ep_state & EP_HAS_STREAMS) {
29362306a36Sopenharmony_ci		if (pep->stream_info.drbls_count >= 2)
29462306a36Sopenharmony_ci			return false;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		pep->stream_info.drbls_count++;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	pep->ep_state &= ~EP_STOPPED;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (pep->idx == 0 && pdev->ep0_stage == CDNSP_DATA_STAGE &&
30262306a36Sopenharmony_ci	    !pdev->ep0_expect_in)
30362306a36Sopenharmony_ci		db_value = DB_VALUE_EP0_OUT(pep->idx, stream_id);
30462306a36Sopenharmony_ci	else
30562306a36Sopenharmony_ci		db_value = DB_VALUE(pep->idx, stream_id);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	trace_cdnsp_tr_drbl(pep, stream_id);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	writel(db_value, reg_addr);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	cdnsp_force_l0_go(pdev);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Doorbell was set. */
31462306a36Sopenharmony_ci	return true;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci/*
31862306a36Sopenharmony_ci * Get the right ring for the given pep and stream_id.
31962306a36Sopenharmony_ci * If the endpoint supports streams, boundary check the USB request's stream ID.
32062306a36Sopenharmony_ci * If the endpoint doesn't support streams, return the singular endpoint ring.
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_cistatic struct cdnsp_ring *cdnsp_get_transfer_ring(struct cdnsp_device *pdev,
32362306a36Sopenharmony_ci						  struct cdnsp_ep *pep,
32462306a36Sopenharmony_ci						  unsigned int stream_id)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	if (!(pep->ep_state & EP_HAS_STREAMS))
32762306a36Sopenharmony_ci		return pep->ring;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (stream_id == 0 || stream_id >= pep->stream_info.num_streams) {
33062306a36Sopenharmony_ci		dev_err(pdev->dev, "ERR: %s ring doesn't exist for SID: %d.\n",
33162306a36Sopenharmony_ci			pep->name, stream_id);
33262306a36Sopenharmony_ci		return NULL;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return pep->stream_info.stream_rings[stream_id];
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic struct cdnsp_ring *
33962306a36Sopenharmony_ci	cdnsp_request_to_transfer_ring(struct cdnsp_device *pdev,
34062306a36Sopenharmony_ci				       struct cdnsp_request *preq)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	return cdnsp_get_transfer_ring(pdev, preq->pep,
34362306a36Sopenharmony_ci				       preq->request.stream_id);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/* Ring the doorbell for any rings with pending requests. */
34762306a36Sopenharmony_civoid cdnsp_ring_doorbell_for_active_rings(struct cdnsp_device *pdev,
34862306a36Sopenharmony_ci					  struct cdnsp_ep *pep)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	struct cdnsp_stream_info *stream_info;
35162306a36Sopenharmony_ci	unsigned int stream_id;
35262306a36Sopenharmony_ci	int ret;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (pep->ep_state & EP_DIS_IN_RROGRESS)
35562306a36Sopenharmony_ci		return;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* A ring has pending Request if its TD list is not empty. */
35862306a36Sopenharmony_ci	if (!(pep->ep_state & EP_HAS_STREAMS) && pep->number) {
35962306a36Sopenharmony_ci		if (pep->ring && !list_empty(&pep->ring->td_list))
36062306a36Sopenharmony_ci			cdnsp_ring_ep_doorbell(pdev, pep, 0);
36162306a36Sopenharmony_ci		return;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	stream_info = &pep->stream_info;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	for (stream_id = 1; stream_id < stream_info->num_streams; stream_id++) {
36762306a36Sopenharmony_ci		struct cdnsp_td *td, *td_temp;
36862306a36Sopenharmony_ci		struct cdnsp_ring *ep_ring;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (stream_info->drbls_count >= 2)
37162306a36Sopenharmony_ci			return;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		ep_ring = cdnsp_get_transfer_ring(pdev, pep, stream_id);
37462306a36Sopenharmony_ci		if (!ep_ring)
37562306a36Sopenharmony_ci			continue;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		if (!ep_ring->stream_active || ep_ring->stream_rejected)
37862306a36Sopenharmony_ci			continue;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		list_for_each_entry_safe(td, td_temp, &ep_ring->td_list,
38162306a36Sopenharmony_ci					 td_list) {
38262306a36Sopenharmony_ci			if (td->drbl)
38362306a36Sopenharmony_ci				continue;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci			ret = cdnsp_ring_ep_doorbell(pdev, pep, stream_id);
38662306a36Sopenharmony_ci			if (ret)
38762306a36Sopenharmony_ci				td->drbl = 1;
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci/*
39362306a36Sopenharmony_ci * Get the hw dequeue pointer controller stopped on, either directly from the
39462306a36Sopenharmony_ci * endpoint context, or if streams are in use from the stream context.
39562306a36Sopenharmony_ci * The returned hw_dequeue contains the lowest four bits with cycle state
39662306a36Sopenharmony_ci * and possible stream context type.
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_cistatic u64 cdnsp_get_hw_deq(struct cdnsp_device *pdev,
39962306a36Sopenharmony_ci			    unsigned int ep_index,
40062306a36Sopenharmony_ci			    unsigned int stream_id)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct cdnsp_stream_ctx *st_ctx;
40362306a36Sopenharmony_ci	struct cdnsp_ep *pep;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	pep = &pdev->eps[stream_id];
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (pep->ep_state & EP_HAS_STREAMS) {
40862306a36Sopenharmony_ci		st_ctx = &pep->stream_info.stream_ctx_array[stream_id];
40962306a36Sopenharmony_ci		return le64_to_cpu(st_ctx->stream_ring);
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return le64_to_cpu(pep->out_ctx->deq);
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/*
41662306a36Sopenharmony_ci * Move the controller endpoint ring dequeue pointer past cur_td.
41762306a36Sopenharmony_ci * Record the new state of the controller endpoint ring dequeue segment,
41862306a36Sopenharmony_ci * dequeue pointer, and new consumer cycle state in state.
41962306a36Sopenharmony_ci * Update internal representation of the ring's dequeue pointer.
42062306a36Sopenharmony_ci *
42162306a36Sopenharmony_ci * We do this in three jumps:
42262306a36Sopenharmony_ci *  - First we update our new ring state to be the same as when the
42362306a36Sopenharmony_ci *    controller stopped.
42462306a36Sopenharmony_ci *  - Then we traverse the ring to find the segment that contains
42562306a36Sopenharmony_ci *    the last TRB in the TD. We toggle the controller new cycle state
42662306a36Sopenharmony_ci *    when we pass any link TRBs with the toggle cycle bit set.
42762306a36Sopenharmony_ci *  - Finally we move the dequeue state one TRB further, toggling the cycle bit
42862306a36Sopenharmony_ci *    if we've moved it past a link TRB with the toggle cycle bit set.
42962306a36Sopenharmony_ci */
43062306a36Sopenharmony_cistatic void cdnsp_find_new_dequeue_state(struct cdnsp_device *pdev,
43162306a36Sopenharmony_ci					 struct cdnsp_ep *pep,
43262306a36Sopenharmony_ci					 unsigned int stream_id,
43362306a36Sopenharmony_ci					 struct cdnsp_td *cur_td,
43462306a36Sopenharmony_ci					 struct cdnsp_dequeue_state *state)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	bool td_last_trb_found = false;
43762306a36Sopenharmony_ci	struct cdnsp_segment *new_seg;
43862306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
43962306a36Sopenharmony_ci	union cdnsp_trb *new_deq;
44062306a36Sopenharmony_ci	bool cycle_found = false;
44162306a36Sopenharmony_ci	u64 hw_dequeue;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	ep_ring = cdnsp_get_transfer_ring(pdev, pep, stream_id);
44462306a36Sopenharmony_ci	if (!ep_ring)
44562306a36Sopenharmony_ci		return;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/*
44862306a36Sopenharmony_ci	 * Dig out the cycle state saved by the controller during the
44962306a36Sopenharmony_ci	 * stop endpoint command.
45062306a36Sopenharmony_ci	 */
45162306a36Sopenharmony_ci	hw_dequeue = cdnsp_get_hw_deq(pdev, pep->idx, stream_id);
45262306a36Sopenharmony_ci	new_seg = ep_ring->deq_seg;
45362306a36Sopenharmony_ci	new_deq = ep_ring->dequeue;
45462306a36Sopenharmony_ci	state->new_cycle_state = hw_dequeue & 0x1;
45562306a36Sopenharmony_ci	state->stream_id = stream_id;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	/*
45862306a36Sopenharmony_ci	 * We want to find the pointer, segment and cycle state of the new trb
45962306a36Sopenharmony_ci	 * (the one after current TD's last_trb). We know the cycle state at
46062306a36Sopenharmony_ci	 * hw_dequeue, so walk the ring until both hw_dequeue and last_trb are
46162306a36Sopenharmony_ci	 * found.
46262306a36Sopenharmony_ci	 */
46362306a36Sopenharmony_ci	do {
46462306a36Sopenharmony_ci		if (!cycle_found && cdnsp_trb_virt_to_dma(new_seg, new_deq)
46562306a36Sopenharmony_ci		    == (dma_addr_t)(hw_dequeue & ~0xf)) {
46662306a36Sopenharmony_ci			cycle_found = true;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci			if (td_last_trb_found)
46962306a36Sopenharmony_ci				break;
47062306a36Sopenharmony_ci		}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		if (new_deq == cur_td->last_trb)
47362306a36Sopenharmony_ci			td_last_trb_found = true;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		if (cycle_found && cdnsp_trb_is_link(new_deq) &&
47662306a36Sopenharmony_ci		    cdnsp_link_trb_toggles_cycle(new_deq))
47762306a36Sopenharmony_ci			state->new_cycle_state ^= 0x1;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		cdnsp_next_trb(pdev, ep_ring, &new_seg, &new_deq);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		/* Search wrapped around, bail out. */
48262306a36Sopenharmony_ci		if (new_deq == pep->ring->dequeue) {
48362306a36Sopenharmony_ci			dev_err(pdev->dev,
48462306a36Sopenharmony_ci				"Error: Failed finding new dequeue state\n");
48562306a36Sopenharmony_ci			state->new_deq_seg = NULL;
48662306a36Sopenharmony_ci			state->new_deq_ptr = NULL;
48762306a36Sopenharmony_ci			return;
48862306a36Sopenharmony_ci		}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	} while (!cycle_found || !td_last_trb_found);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	state->new_deq_seg = new_seg;
49362306a36Sopenharmony_ci	state->new_deq_ptr = new_deq;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	trace_cdnsp_new_deq_state(state);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci/*
49962306a36Sopenharmony_ci * flip_cycle means flip the cycle bit of all but the first and last TRB.
50062306a36Sopenharmony_ci * (The last TRB actually points to the ring enqueue pointer, which is not part
50162306a36Sopenharmony_ci * of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
50262306a36Sopenharmony_ci */
50362306a36Sopenharmony_cistatic void cdnsp_td_to_noop(struct cdnsp_device *pdev,
50462306a36Sopenharmony_ci			     struct cdnsp_ring *ep_ring,
50562306a36Sopenharmony_ci			     struct cdnsp_td *td,
50662306a36Sopenharmony_ci			     bool flip_cycle)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct cdnsp_segment *seg = td->start_seg;
50962306a36Sopenharmony_ci	union cdnsp_trb *trb = td->first_trb;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	while (1) {
51262306a36Sopenharmony_ci		cdnsp_trb_to_noop(trb, TRB_TR_NOOP);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		/* flip cycle if asked to */
51562306a36Sopenharmony_ci		if (flip_cycle && trb != td->first_trb && trb != td->last_trb)
51662306a36Sopenharmony_ci			trb->generic.field[3] ^= cpu_to_le32(TRB_CYCLE);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		if (trb == td->last_trb)
51962306a36Sopenharmony_ci			break;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		cdnsp_next_trb(pdev, ep_ring, &seg, &trb);
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci/*
52662306a36Sopenharmony_ci * This TD is defined by the TRBs starting at start_trb in start_seg and ending
52762306a36Sopenharmony_ci * at end_trb, which may be in another segment. If the suspect DMA address is a
52862306a36Sopenharmony_ci * TRB in this TD, this function returns that TRB's segment. Otherwise it
52962306a36Sopenharmony_ci * returns 0.
53062306a36Sopenharmony_ci */
53162306a36Sopenharmony_cistatic struct cdnsp_segment *cdnsp_trb_in_td(struct cdnsp_device *pdev,
53262306a36Sopenharmony_ci					     struct cdnsp_segment *start_seg,
53362306a36Sopenharmony_ci					     union cdnsp_trb *start_trb,
53462306a36Sopenharmony_ci					     union cdnsp_trb *end_trb,
53562306a36Sopenharmony_ci					     dma_addr_t suspect_dma)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct cdnsp_segment *cur_seg;
53862306a36Sopenharmony_ci	union cdnsp_trb *temp_trb;
53962306a36Sopenharmony_ci	dma_addr_t end_seg_dma;
54062306a36Sopenharmony_ci	dma_addr_t end_trb_dma;
54162306a36Sopenharmony_ci	dma_addr_t start_dma;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	start_dma = cdnsp_trb_virt_to_dma(start_seg, start_trb);
54462306a36Sopenharmony_ci	cur_seg = start_seg;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	do {
54762306a36Sopenharmony_ci		if (start_dma == 0)
54862306a36Sopenharmony_ci			return NULL;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		temp_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1];
55162306a36Sopenharmony_ci		/* We may get an event for a Link TRB in the middle of a TD */
55262306a36Sopenharmony_ci		end_seg_dma = cdnsp_trb_virt_to_dma(cur_seg, temp_trb);
55362306a36Sopenharmony_ci		/* If the end TRB isn't in this segment, this is set to 0 */
55462306a36Sopenharmony_ci		end_trb_dma = cdnsp_trb_virt_to_dma(cur_seg, end_trb);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		trace_cdnsp_looking_trb_in_td(suspect_dma, start_dma,
55762306a36Sopenharmony_ci					      end_trb_dma, cur_seg->dma,
55862306a36Sopenharmony_ci					      end_seg_dma);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci		if (end_trb_dma > 0) {
56162306a36Sopenharmony_ci			/*
56262306a36Sopenharmony_ci			 * The end TRB is in this segment, so suspect should
56362306a36Sopenharmony_ci			 * be here
56462306a36Sopenharmony_ci			 */
56562306a36Sopenharmony_ci			if (start_dma <= end_trb_dma) {
56662306a36Sopenharmony_ci				if (suspect_dma >= start_dma &&
56762306a36Sopenharmony_ci				    suspect_dma <= end_trb_dma) {
56862306a36Sopenharmony_ci					return cur_seg;
56962306a36Sopenharmony_ci				}
57062306a36Sopenharmony_ci			} else {
57162306a36Sopenharmony_ci				/*
57262306a36Sopenharmony_ci				 * Case for one segment with a
57362306a36Sopenharmony_ci				 * TD wrapped around to the top
57462306a36Sopenharmony_ci				 */
57562306a36Sopenharmony_ci				if ((suspect_dma >= start_dma &&
57662306a36Sopenharmony_ci				     suspect_dma <= end_seg_dma) ||
57762306a36Sopenharmony_ci				    (suspect_dma >= cur_seg->dma &&
57862306a36Sopenharmony_ci				     suspect_dma <= end_trb_dma)) {
57962306a36Sopenharmony_ci					return cur_seg;
58062306a36Sopenharmony_ci				}
58162306a36Sopenharmony_ci			}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci			return NULL;
58462306a36Sopenharmony_ci		}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci		/* Might still be somewhere in this segment */
58762306a36Sopenharmony_ci		if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma)
58862306a36Sopenharmony_ci			return cur_seg;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		cur_seg = cur_seg->next;
59162306a36Sopenharmony_ci		start_dma = cdnsp_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
59262306a36Sopenharmony_ci	} while (cur_seg != start_seg);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	return NULL;
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic void cdnsp_unmap_td_bounce_buffer(struct cdnsp_device *pdev,
59862306a36Sopenharmony_ci					 struct cdnsp_ring *ring,
59962306a36Sopenharmony_ci					 struct cdnsp_td *td)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct cdnsp_segment *seg = td->bounce_seg;
60262306a36Sopenharmony_ci	struct cdnsp_request *preq;
60362306a36Sopenharmony_ci	size_t len;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (!seg)
60662306a36Sopenharmony_ci		return;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	preq = td->preq;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	trace_cdnsp_bounce_unmap(td->preq, seg->bounce_len, seg->bounce_offs,
61162306a36Sopenharmony_ci				 seg->bounce_dma, 0);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (!preq->direction) {
61462306a36Sopenharmony_ci		dma_unmap_single(pdev->dev, seg->bounce_dma,
61562306a36Sopenharmony_ci				 ring->bounce_buf_len,  DMA_TO_DEVICE);
61662306a36Sopenharmony_ci		return;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	dma_unmap_single(pdev->dev, seg->bounce_dma, ring->bounce_buf_len,
62062306a36Sopenharmony_ci			 DMA_FROM_DEVICE);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* For in transfers we need to copy the data from bounce to sg */
62362306a36Sopenharmony_ci	len = sg_pcopy_from_buffer(preq->request.sg, preq->request.num_sgs,
62462306a36Sopenharmony_ci				   seg->bounce_buf, seg->bounce_len,
62562306a36Sopenharmony_ci				   seg->bounce_offs);
62662306a36Sopenharmony_ci	if (len != seg->bounce_len)
62762306a36Sopenharmony_ci		dev_warn(pdev->dev, "WARN Wrong bounce buffer read length: %zu != %d\n",
62862306a36Sopenharmony_ci			 len, seg->bounce_len);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	seg->bounce_len = 0;
63162306a36Sopenharmony_ci	seg->bounce_offs = 0;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic int cdnsp_cmd_set_deq(struct cdnsp_device *pdev,
63562306a36Sopenharmony_ci			     struct cdnsp_ep *pep,
63662306a36Sopenharmony_ci			     struct cdnsp_dequeue_state *deq_state)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
63962306a36Sopenharmony_ci	int ret;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (!deq_state->new_deq_ptr || !deq_state->new_deq_seg) {
64262306a36Sopenharmony_ci		cdnsp_ring_doorbell_for_active_rings(pdev, pep);
64362306a36Sopenharmony_ci		return 0;
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	cdnsp_queue_new_dequeue_state(pdev, pep, deq_state);
64762306a36Sopenharmony_ci	cdnsp_ring_cmd_db(pdev);
64862306a36Sopenharmony_ci	ret = cdnsp_wait_for_cmd_compl(pdev);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	trace_cdnsp_handle_cmd_set_deq(cdnsp_get_slot_ctx(&pdev->out_ctx));
65162306a36Sopenharmony_ci	trace_cdnsp_handle_cmd_set_deq_ep(pep->out_ctx);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/*
65462306a36Sopenharmony_ci	 * Update the ring's dequeue segment and dequeue pointer
65562306a36Sopenharmony_ci	 * to reflect the new position.
65662306a36Sopenharmony_ci	 */
65762306a36Sopenharmony_ci	ep_ring = cdnsp_get_transfer_ring(pdev, pep, deq_state->stream_id);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (cdnsp_trb_is_link(ep_ring->dequeue)) {
66062306a36Sopenharmony_ci		ep_ring->deq_seg = ep_ring->deq_seg->next;
66162306a36Sopenharmony_ci		ep_ring->dequeue = ep_ring->deq_seg->trbs;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	while (ep_ring->dequeue != deq_state->new_deq_ptr) {
66562306a36Sopenharmony_ci		ep_ring->num_trbs_free++;
66662306a36Sopenharmony_ci		ep_ring->dequeue++;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		if (cdnsp_trb_is_link(ep_ring->dequeue)) {
66962306a36Sopenharmony_ci			if (ep_ring->dequeue == deq_state->new_deq_ptr)
67062306a36Sopenharmony_ci				break;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci			ep_ring->deq_seg = ep_ring->deq_seg->next;
67362306a36Sopenharmony_ci			ep_ring->dequeue = ep_ring->deq_seg->trbs;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	/*
67862306a36Sopenharmony_ci	 * Probably there was TIMEOUT during handling Set Dequeue Pointer
67962306a36Sopenharmony_ci	 * command. It's critical error and controller will be stopped.
68062306a36Sopenharmony_ci	 */
68162306a36Sopenharmony_ci	if (ret)
68262306a36Sopenharmony_ci		return -ESHUTDOWN;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Restart any rings with pending requests */
68562306a36Sopenharmony_ci	cdnsp_ring_doorbell_for_active_rings(pdev, pep);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	return 0;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ciint cdnsp_remove_request(struct cdnsp_device *pdev,
69162306a36Sopenharmony_ci			 struct cdnsp_request *preq,
69262306a36Sopenharmony_ci			 struct cdnsp_ep *pep)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct cdnsp_dequeue_state deq_state;
69562306a36Sopenharmony_ci	struct cdnsp_td *cur_td = NULL;
69662306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
69762306a36Sopenharmony_ci	struct cdnsp_segment *seg;
69862306a36Sopenharmony_ci	int status = -ECONNRESET;
69962306a36Sopenharmony_ci	int ret = 0;
70062306a36Sopenharmony_ci	u64 hw_deq;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	memset(&deq_state, 0, sizeof(deq_state));
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	trace_cdnsp_remove_request(pep->out_ctx);
70562306a36Sopenharmony_ci	trace_cdnsp_remove_request_td(preq);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	cur_td = &preq->td;
70862306a36Sopenharmony_ci	ep_ring = cdnsp_request_to_transfer_ring(pdev, preq);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	/*
71162306a36Sopenharmony_ci	 * If we stopped on the TD we need to cancel, then we have to
71262306a36Sopenharmony_ci	 * move the controller endpoint ring dequeue pointer past
71362306a36Sopenharmony_ci	 * this TD.
71462306a36Sopenharmony_ci	 */
71562306a36Sopenharmony_ci	hw_deq = cdnsp_get_hw_deq(pdev, pep->idx, preq->request.stream_id);
71662306a36Sopenharmony_ci	hw_deq &= ~0xf;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	seg = cdnsp_trb_in_td(pdev, cur_td->start_seg, cur_td->first_trb,
71962306a36Sopenharmony_ci			      cur_td->last_trb, hw_deq);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (seg && (pep->ep_state & EP_ENABLED))
72262306a36Sopenharmony_ci		cdnsp_find_new_dequeue_state(pdev, pep, preq->request.stream_id,
72362306a36Sopenharmony_ci					     cur_td, &deq_state);
72462306a36Sopenharmony_ci	else
72562306a36Sopenharmony_ci		cdnsp_td_to_noop(pdev, ep_ring, cur_td, false);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/*
72862306a36Sopenharmony_ci	 * The event handler won't see a completion for this TD anymore,
72962306a36Sopenharmony_ci	 * so remove it from the endpoint ring's TD list.
73062306a36Sopenharmony_ci	 */
73162306a36Sopenharmony_ci	list_del_init(&cur_td->td_list);
73262306a36Sopenharmony_ci	ep_ring->num_tds--;
73362306a36Sopenharmony_ci	pep->stream_info.td_count--;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/*
73662306a36Sopenharmony_ci	 * During disconnecting all endpoint will be disabled so we don't
73762306a36Sopenharmony_ci	 * have to worry about updating dequeue pointer.
73862306a36Sopenharmony_ci	 */
73962306a36Sopenharmony_ci	if (pdev->cdnsp_state & CDNSP_STATE_DISCONNECT_PENDING) {
74062306a36Sopenharmony_ci		status = -ESHUTDOWN;
74162306a36Sopenharmony_ci		ret = cdnsp_cmd_set_deq(pdev, pep, &deq_state);
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	cdnsp_unmap_td_bounce_buffer(pdev, ep_ring, cur_td);
74562306a36Sopenharmony_ci	cdnsp_gadget_giveback(pep, cur_td->preq, status);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return ret;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic int cdnsp_update_port_id(struct cdnsp_device *pdev, u32 port_id)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	struct cdnsp_port *port = pdev->active_port;
75362306a36Sopenharmony_ci	u8 old_port = 0;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (port && port->port_num == port_id)
75662306a36Sopenharmony_ci		return 0;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	if (port)
75962306a36Sopenharmony_ci		old_port = port->port_num;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (port_id == pdev->usb2_port.port_num) {
76262306a36Sopenharmony_ci		port = &pdev->usb2_port;
76362306a36Sopenharmony_ci	} else if (port_id == pdev->usb3_port.port_num) {
76462306a36Sopenharmony_ci		port  = &pdev->usb3_port;
76562306a36Sopenharmony_ci	} else {
76662306a36Sopenharmony_ci		dev_err(pdev->dev, "Port event with invalid port ID %d\n",
76762306a36Sopenharmony_ci			port_id);
76862306a36Sopenharmony_ci		return -EINVAL;
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (port_id != old_port) {
77262306a36Sopenharmony_ci		cdnsp_disable_slot(pdev);
77362306a36Sopenharmony_ci		pdev->active_port = port;
77462306a36Sopenharmony_ci		cdnsp_enable_slot(pdev);
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if (port_id == pdev->usb2_port.port_num)
77862306a36Sopenharmony_ci		cdnsp_set_usb2_hardware_lpm(pdev, NULL, 1);
77962306a36Sopenharmony_ci	else
78062306a36Sopenharmony_ci		writel(PORT_U1_TIMEOUT(1) | PORT_U2_TIMEOUT(1),
78162306a36Sopenharmony_ci		       &pdev->usb3_port.regs->portpmsc);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	return 0;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic void cdnsp_handle_port_status(struct cdnsp_device *pdev,
78762306a36Sopenharmony_ci				     union cdnsp_trb *event)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct cdnsp_port_regs __iomem *port_regs;
79062306a36Sopenharmony_ci	u32 portsc, cmd_regs;
79162306a36Sopenharmony_ci	bool port2 = false;
79262306a36Sopenharmony_ci	u32 link_state;
79362306a36Sopenharmony_ci	u32 port_id;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	/* Port status change events always have a successful completion code */
79662306a36Sopenharmony_ci	if (GET_COMP_CODE(le32_to_cpu(event->generic.field[2])) != COMP_SUCCESS)
79762306a36Sopenharmony_ci		dev_err(pdev->dev, "ERR: incorrect PSC event\n");
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	port_id = GET_PORT_ID(le32_to_cpu(event->generic.field[0]));
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (cdnsp_update_port_id(pdev, port_id))
80262306a36Sopenharmony_ci		goto cleanup;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	port_regs = pdev->active_port->regs;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (port_id == pdev->usb2_port.port_num)
80762306a36Sopenharmony_ci		port2 = true;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_cinew_event:
81062306a36Sopenharmony_ci	portsc = readl(&port_regs->portsc);
81162306a36Sopenharmony_ci	writel(cdnsp_port_state_to_neutral(portsc) |
81262306a36Sopenharmony_ci	       (portsc & PORT_CHANGE_BITS), &port_regs->portsc);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	trace_cdnsp_handle_port_status(pdev->active_port->port_num, portsc);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	pdev->gadget.speed = cdnsp_port_speed(portsc);
81762306a36Sopenharmony_ci	link_state = portsc & PORT_PLS_MASK;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/* Port Link State change detected. */
82062306a36Sopenharmony_ci	if ((portsc & PORT_PLC)) {
82162306a36Sopenharmony_ci		if (!(pdev->cdnsp_state & CDNSP_WAKEUP_PENDING)  &&
82262306a36Sopenharmony_ci		    link_state == XDEV_RESUME) {
82362306a36Sopenharmony_ci			cmd_regs = readl(&pdev->op_regs->command);
82462306a36Sopenharmony_ci			if (!(cmd_regs & CMD_R_S))
82562306a36Sopenharmony_ci				goto cleanup;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci			if (DEV_SUPERSPEED_ANY(portsc)) {
82862306a36Sopenharmony_ci				cdnsp_set_link_state(pdev, &port_regs->portsc,
82962306a36Sopenharmony_ci						     XDEV_U0);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci				cdnsp_resume_gadget(pdev);
83262306a36Sopenharmony_ci			}
83362306a36Sopenharmony_ci		}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		if ((pdev->cdnsp_state & CDNSP_WAKEUP_PENDING) &&
83662306a36Sopenharmony_ci		    link_state == XDEV_U0) {
83762306a36Sopenharmony_ci			pdev->cdnsp_state &= ~CDNSP_WAKEUP_PENDING;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci			cdnsp_force_header_wakeup(pdev, 1);
84062306a36Sopenharmony_ci			cdnsp_ring_cmd_db(pdev);
84162306a36Sopenharmony_ci			cdnsp_wait_for_cmd_compl(pdev);
84262306a36Sopenharmony_ci		}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci		if (link_state == XDEV_U0 && pdev->link_state == XDEV_U3 &&
84562306a36Sopenharmony_ci		    !DEV_SUPERSPEED_ANY(portsc))
84662306a36Sopenharmony_ci			cdnsp_resume_gadget(pdev);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		if (link_state == XDEV_U3 &&  pdev->link_state != XDEV_U3)
84962306a36Sopenharmony_ci			cdnsp_suspend_gadget(pdev);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		pdev->link_state = link_state;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	if (portsc & PORT_CSC) {
85562306a36Sopenharmony_ci		/* Detach device. */
85662306a36Sopenharmony_ci		if (pdev->gadget.connected && !(portsc & PORT_CONNECT))
85762306a36Sopenharmony_ci			cdnsp_disconnect_gadget(pdev);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci		/* Attach device. */
86062306a36Sopenharmony_ci		if (portsc & PORT_CONNECT) {
86162306a36Sopenharmony_ci			if (!port2)
86262306a36Sopenharmony_ci				cdnsp_irq_reset(pdev);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci			usb_gadget_set_state(&pdev->gadget, USB_STATE_ATTACHED);
86562306a36Sopenharmony_ci		}
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* Port reset. */
86962306a36Sopenharmony_ci	if ((portsc & (PORT_RC | PORT_WRC)) && (portsc & PORT_CONNECT)) {
87062306a36Sopenharmony_ci		cdnsp_irq_reset(pdev);
87162306a36Sopenharmony_ci		pdev->u1_allowed = 0;
87262306a36Sopenharmony_ci		pdev->u2_allowed = 0;
87362306a36Sopenharmony_ci		pdev->may_wakeup = 0;
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (portsc & PORT_CEC)
87762306a36Sopenharmony_ci		dev_err(pdev->dev, "Port Over Current detected\n");
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (portsc & PORT_CEC)
88062306a36Sopenharmony_ci		dev_err(pdev->dev, "Port Configure Error detected\n");
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (readl(&port_regs->portsc) & PORT_CHANGE_BITS)
88362306a36Sopenharmony_ci		goto new_event;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cicleanup:
88662306a36Sopenharmony_ci	cdnsp_inc_deq(pdev, pdev->event_ring);
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic void cdnsp_td_cleanup(struct cdnsp_device *pdev,
89062306a36Sopenharmony_ci			     struct cdnsp_td *td,
89162306a36Sopenharmony_ci			     struct cdnsp_ring *ep_ring,
89262306a36Sopenharmony_ci			     int *status)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	struct cdnsp_request *preq = td->preq;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	/* if a bounce buffer was used to align this td then unmap it */
89762306a36Sopenharmony_ci	cdnsp_unmap_td_bounce_buffer(pdev, ep_ring, td);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	/*
90062306a36Sopenharmony_ci	 * If the controller said we transferred more data than the buffer
90162306a36Sopenharmony_ci	 * length, Play it safe and say we didn't transfer anything.
90262306a36Sopenharmony_ci	 */
90362306a36Sopenharmony_ci	if (preq->request.actual > preq->request.length) {
90462306a36Sopenharmony_ci		preq->request.actual = 0;
90562306a36Sopenharmony_ci		*status = 0;
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	list_del_init(&td->td_list);
90962306a36Sopenharmony_ci	ep_ring->num_tds--;
91062306a36Sopenharmony_ci	preq->pep->stream_info.td_count--;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	cdnsp_gadget_giveback(preq->pep, preq, *status);
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic void cdnsp_finish_td(struct cdnsp_device *pdev,
91662306a36Sopenharmony_ci			    struct cdnsp_td *td,
91762306a36Sopenharmony_ci			    struct cdnsp_transfer_event *event,
91862306a36Sopenharmony_ci			    struct cdnsp_ep *ep,
91962306a36Sopenharmony_ci			    int *status)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
92262306a36Sopenharmony_ci	u32 trb_comp_code;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	ep_ring = cdnsp_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
92562306a36Sopenharmony_ci	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID ||
92862306a36Sopenharmony_ci	    trb_comp_code == COMP_STOPPED ||
92962306a36Sopenharmony_ci	    trb_comp_code == COMP_STOPPED_SHORT_PACKET) {
93062306a36Sopenharmony_ci		/*
93162306a36Sopenharmony_ci		 * The Endpoint Stop Command completion will take care of any
93262306a36Sopenharmony_ci		 * stopped TDs. A stopped TD may be restarted, so don't update
93362306a36Sopenharmony_ci		 * the ring dequeue pointer or take this TD off any lists yet.
93462306a36Sopenharmony_ci		 */
93562306a36Sopenharmony_ci		return;
93662306a36Sopenharmony_ci	}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	/* Update ring dequeue pointer */
93962306a36Sopenharmony_ci	while (ep_ring->dequeue != td->last_trb)
94062306a36Sopenharmony_ci		cdnsp_inc_deq(pdev, ep_ring);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	cdnsp_inc_deq(pdev, ep_ring);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	cdnsp_td_cleanup(pdev, td, ep_ring, status);
94562306a36Sopenharmony_ci}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci/* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */
94862306a36Sopenharmony_cistatic int cdnsp_sum_trb_lengths(struct cdnsp_device *pdev,
94962306a36Sopenharmony_ci				 struct cdnsp_ring *ring,
95062306a36Sopenharmony_ci				 union cdnsp_trb *stop_trb)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	struct cdnsp_segment *seg = ring->deq_seg;
95362306a36Sopenharmony_ci	union cdnsp_trb *trb = ring->dequeue;
95462306a36Sopenharmony_ci	u32 sum;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	for (sum = 0; trb != stop_trb; cdnsp_next_trb(pdev, ring, &seg, &trb)) {
95762306a36Sopenharmony_ci		if (!cdnsp_trb_is_noop(trb) && !cdnsp_trb_is_link(trb))
95862306a36Sopenharmony_ci			sum += TRB_LEN(le32_to_cpu(trb->generic.field[2]));
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci	return sum;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic int cdnsp_giveback_first_trb(struct cdnsp_device *pdev,
96462306a36Sopenharmony_ci				    struct cdnsp_ep *pep,
96562306a36Sopenharmony_ci				    unsigned int stream_id,
96662306a36Sopenharmony_ci				    int start_cycle,
96762306a36Sopenharmony_ci				    struct cdnsp_generic_trb *start_trb)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	/*
97062306a36Sopenharmony_ci	 * Pass all the TRBs to the hardware at once and make sure this write
97162306a36Sopenharmony_ci	 * isn't reordered.
97262306a36Sopenharmony_ci	 */
97362306a36Sopenharmony_ci	wmb();
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (start_cycle)
97662306a36Sopenharmony_ci		start_trb->field[3] |= cpu_to_le32(start_cycle);
97762306a36Sopenharmony_ci	else
97862306a36Sopenharmony_ci		start_trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if ((pep->ep_state & EP_HAS_STREAMS) &&
98162306a36Sopenharmony_ci	    !pep->stream_info.first_prime_det) {
98262306a36Sopenharmony_ci		trace_cdnsp_wait_for_prime(pep, stream_id);
98362306a36Sopenharmony_ci		return 0;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	return cdnsp_ring_ep_doorbell(pdev, pep, stream_id);
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci/*
99062306a36Sopenharmony_ci * Process control tds, update USB request status and actual_length.
99162306a36Sopenharmony_ci */
99262306a36Sopenharmony_cistatic void cdnsp_process_ctrl_td(struct cdnsp_device *pdev,
99362306a36Sopenharmony_ci				  struct cdnsp_td *td,
99462306a36Sopenharmony_ci				  union cdnsp_trb *event_trb,
99562306a36Sopenharmony_ci				  struct cdnsp_transfer_event *event,
99662306a36Sopenharmony_ci				  struct cdnsp_ep *pep,
99762306a36Sopenharmony_ci				  int *status)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
100062306a36Sopenharmony_ci	u32 remaining;
100162306a36Sopenharmony_ci	u32 trb_type;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(event_trb->generic.field[3]));
100462306a36Sopenharmony_ci	ep_ring = cdnsp_dma_to_transfer_ring(pep, le64_to_cpu(event->buffer));
100562306a36Sopenharmony_ci	remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	/*
100862306a36Sopenharmony_ci	 * if on data stage then update the actual_length of the USB
100962306a36Sopenharmony_ci	 * request and flag it as set, so it won't be overwritten in the event
101062306a36Sopenharmony_ci	 * for the last TRB.
101162306a36Sopenharmony_ci	 */
101262306a36Sopenharmony_ci	if (trb_type == TRB_DATA) {
101362306a36Sopenharmony_ci		td->request_length_set = true;
101462306a36Sopenharmony_ci		td->preq->request.actual = td->preq->request.length - remaining;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/* at status stage */
101862306a36Sopenharmony_ci	if (!td->request_length_set)
101962306a36Sopenharmony_ci		td->preq->request.actual = td->preq->request.length;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (pdev->ep0_stage == CDNSP_DATA_STAGE && pep->number == 0 &&
102262306a36Sopenharmony_ci	    pdev->three_stage_setup) {
102362306a36Sopenharmony_ci		td = list_entry(ep_ring->td_list.next, struct cdnsp_td,
102462306a36Sopenharmony_ci				td_list);
102562306a36Sopenharmony_ci		pdev->ep0_stage = CDNSP_STATUS_STAGE;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci		cdnsp_giveback_first_trb(pdev, pep, 0, ep_ring->cycle_state,
102862306a36Sopenharmony_ci					 &td->last_trb->generic);
102962306a36Sopenharmony_ci		return;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	*status = 0;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	cdnsp_finish_td(pdev, td, event, pep, status);
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci/*
103862306a36Sopenharmony_ci * Process isochronous tds, update usb request status and actual_length.
103962306a36Sopenharmony_ci */
104062306a36Sopenharmony_cistatic void cdnsp_process_isoc_td(struct cdnsp_device *pdev,
104162306a36Sopenharmony_ci				  struct cdnsp_td *td,
104262306a36Sopenharmony_ci				  union cdnsp_trb *ep_trb,
104362306a36Sopenharmony_ci				  struct cdnsp_transfer_event *event,
104462306a36Sopenharmony_ci				  struct cdnsp_ep *pep,
104562306a36Sopenharmony_ci				  int status)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct cdnsp_request *preq = td->preq;
104862306a36Sopenharmony_ci	u32 remaining, requested, ep_trb_len;
104962306a36Sopenharmony_ci	bool sum_trbs_for_length = false;
105062306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
105162306a36Sopenharmony_ci	u32 trb_comp_code;
105262306a36Sopenharmony_ci	u32 td_length;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	ep_ring = cdnsp_dma_to_transfer_ring(pep, le64_to_cpu(event->buffer));
105562306a36Sopenharmony_ci	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
105662306a36Sopenharmony_ci	remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
105762306a36Sopenharmony_ci	ep_trb_len = TRB_LEN(le32_to_cpu(ep_trb->generic.field[2]));
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	requested = preq->request.length;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	/* handle completion code */
106262306a36Sopenharmony_ci	switch (trb_comp_code) {
106362306a36Sopenharmony_ci	case COMP_SUCCESS:
106462306a36Sopenharmony_ci		preq->request.status = 0;
106562306a36Sopenharmony_ci		break;
106662306a36Sopenharmony_ci	case COMP_SHORT_PACKET:
106762306a36Sopenharmony_ci		preq->request.status = 0;
106862306a36Sopenharmony_ci		sum_trbs_for_length = true;
106962306a36Sopenharmony_ci		break;
107062306a36Sopenharmony_ci	case COMP_ISOCH_BUFFER_OVERRUN:
107162306a36Sopenharmony_ci	case COMP_BABBLE_DETECTED_ERROR:
107262306a36Sopenharmony_ci		preq->request.status = -EOVERFLOW;
107362306a36Sopenharmony_ci		break;
107462306a36Sopenharmony_ci	case COMP_STOPPED:
107562306a36Sopenharmony_ci		sum_trbs_for_length = true;
107662306a36Sopenharmony_ci		break;
107762306a36Sopenharmony_ci	case COMP_STOPPED_SHORT_PACKET:
107862306a36Sopenharmony_ci		/* field normally containing residue now contains transferred */
107962306a36Sopenharmony_ci		preq->request.status  = 0;
108062306a36Sopenharmony_ci		requested = remaining;
108162306a36Sopenharmony_ci		break;
108262306a36Sopenharmony_ci	case COMP_STOPPED_LENGTH_INVALID:
108362306a36Sopenharmony_ci		requested = 0;
108462306a36Sopenharmony_ci		remaining = 0;
108562306a36Sopenharmony_ci		break;
108662306a36Sopenharmony_ci	default:
108762306a36Sopenharmony_ci		sum_trbs_for_length = true;
108862306a36Sopenharmony_ci		preq->request.status = -1;
108962306a36Sopenharmony_ci		break;
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (sum_trbs_for_length) {
109362306a36Sopenharmony_ci		td_length = cdnsp_sum_trb_lengths(pdev, ep_ring, ep_trb);
109462306a36Sopenharmony_ci		td_length += ep_trb_len - remaining;
109562306a36Sopenharmony_ci	} else {
109662306a36Sopenharmony_ci		td_length = requested;
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	td->preq->request.actual += td_length;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	cdnsp_finish_td(pdev, td, event, pep, &status);
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cistatic void cdnsp_skip_isoc_td(struct cdnsp_device *pdev,
110562306a36Sopenharmony_ci			       struct cdnsp_td *td,
110662306a36Sopenharmony_ci			       struct cdnsp_transfer_event *event,
110762306a36Sopenharmony_ci			       struct cdnsp_ep *pep,
110862306a36Sopenharmony_ci			       int status)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	ep_ring = cdnsp_dma_to_transfer_ring(pep, le64_to_cpu(event->buffer));
111362306a36Sopenharmony_ci	td->preq->request.status = -EXDEV;
111462306a36Sopenharmony_ci	td->preq->request.actual = 0;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	/* Update ring dequeue pointer */
111762306a36Sopenharmony_ci	while (ep_ring->dequeue != td->last_trb)
111862306a36Sopenharmony_ci		cdnsp_inc_deq(pdev, ep_ring);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	cdnsp_inc_deq(pdev, ep_ring);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	cdnsp_td_cleanup(pdev, td, ep_ring, &status);
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci/*
112662306a36Sopenharmony_ci * Process bulk and interrupt tds, update usb request status and actual_length.
112762306a36Sopenharmony_ci */
112862306a36Sopenharmony_cistatic void cdnsp_process_bulk_intr_td(struct cdnsp_device *pdev,
112962306a36Sopenharmony_ci				       struct cdnsp_td *td,
113062306a36Sopenharmony_ci				       union cdnsp_trb *ep_trb,
113162306a36Sopenharmony_ci				       struct cdnsp_transfer_event *event,
113262306a36Sopenharmony_ci				       struct cdnsp_ep *ep,
113362306a36Sopenharmony_ci				       int *status)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	u32 remaining, requested, ep_trb_len;
113662306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
113762306a36Sopenharmony_ci	u32 trb_comp_code;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	ep_ring = cdnsp_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer));
114062306a36Sopenharmony_ci	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
114162306a36Sopenharmony_ci	remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
114262306a36Sopenharmony_ci	ep_trb_len = TRB_LEN(le32_to_cpu(ep_trb->generic.field[2]));
114362306a36Sopenharmony_ci	requested = td->preq->request.length;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	switch (trb_comp_code) {
114662306a36Sopenharmony_ci	case COMP_SUCCESS:
114762306a36Sopenharmony_ci	case COMP_SHORT_PACKET:
114862306a36Sopenharmony_ci		*status = 0;
114962306a36Sopenharmony_ci		break;
115062306a36Sopenharmony_ci	case COMP_STOPPED_SHORT_PACKET:
115162306a36Sopenharmony_ci		td->preq->request.actual = remaining;
115262306a36Sopenharmony_ci		goto finish_td;
115362306a36Sopenharmony_ci	case COMP_STOPPED_LENGTH_INVALID:
115462306a36Sopenharmony_ci		/* Stopped on ep trb with invalid length, exclude it. */
115562306a36Sopenharmony_ci		ep_trb_len = 0;
115662306a36Sopenharmony_ci		remaining = 0;
115762306a36Sopenharmony_ci		break;
115862306a36Sopenharmony_ci	}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	if (ep_trb == td->last_trb)
116162306a36Sopenharmony_ci		ep_trb_len = requested - remaining;
116262306a36Sopenharmony_ci	else
116362306a36Sopenharmony_ci		ep_trb_len = cdnsp_sum_trb_lengths(pdev, ep_ring, ep_trb) +
116462306a36Sopenharmony_ci						   ep_trb_len - remaining;
116562306a36Sopenharmony_ci	td->preq->request.actual = ep_trb_len;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_cifinish_td:
116862306a36Sopenharmony_ci	ep->stream_info.drbls_count--;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	cdnsp_finish_td(pdev, td, event, ep, status);
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic void cdnsp_handle_tx_nrdy(struct cdnsp_device *pdev,
117462306a36Sopenharmony_ci				 struct cdnsp_transfer_event *event)
117562306a36Sopenharmony_ci{
117662306a36Sopenharmony_ci	struct cdnsp_generic_trb *generic;
117762306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
117862306a36Sopenharmony_ci	struct cdnsp_ep *pep;
117962306a36Sopenharmony_ci	int cur_stream;
118062306a36Sopenharmony_ci	int ep_index;
118162306a36Sopenharmony_ci	int host_sid;
118262306a36Sopenharmony_ci	int dev_sid;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	generic = (struct cdnsp_generic_trb *)event;
118562306a36Sopenharmony_ci	ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
118662306a36Sopenharmony_ci	dev_sid = TRB_TO_DEV_STREAM(le32_to_cpu(generic->field[0]));
118762306a36Sopenharmony_ci	host_sid = TRB_TO_HOST_STREAM(le32_to_cpu(generic->field[2]));
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	pep = &pdev->eps[ep_index];
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	if (!(pep->ep_state & EP_HAS_STREAMS))
119262306a36Sopenharmony_ci		return;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	if (host_sid == STREAM_PRIME_ACK) {
119562306a36Sopenharmony_ci		pep->stream_info.first_prime_det = 1;
119662306a36Sopenharmony_ci		for (cur_stream = 1; cur_stream < pep->stream_info.num_streams;
119762306a36Sopenharmony_ci		    cur_stream++) {
119862306a36Sopenharmony_ci			ep_ring = pep->stream_info.stream_rings[cur_stream];
119962306a36Sopenharmony_ci			ep_ring->stream_active = 1;
120062306a36Sopenharmony_ci			ep_ring->stream_rejected = 0;
120162306a36Sopenharmony_ci		}
120262306a36Sopenharmony_ci	}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (host_sid == STREAM_REJECTED) {
120562306a36Sopenharmony_ci		struct cdnsp_td *td, *td_temp;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci		pep->stream_info.drbls_count--;
120862306a36Sopenharmony_ci		ep_ring = pep->stream_info.stream_rings[dev_sid];
120962306a36Sopenharmony_ci		ep_ring->stream_active = 0;
121062306a36Sopenharmony_ci		ep_ring->stream_rejected = 1;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci		list_for_each_entry_safe(td, td_temp, &ep_ring->td_list,
121362306a36Sopenharmony_ci					 td_list) {
121462306a36Sopenharmony_ci			td->drbl = 0;
121562306a36Sopenharmony_ci		}
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	cdnsp_ring_doorbell_for_active_rings(pdev, pep);
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci/*
122262306a36Sopenharmony_ci * If this function returns an error condition, it means it got a Transfer
122362306a36Sopenharmony_ci * event with a corrupted TRB DMA address or endpoint is disabled.
122462306a36Sopenharmony_ci */
122562306a36Sopenharmony_cistatic int cdnsp_handle_tx_event(struct cdnsp_device *pdev,
122662306a36Sopenharmony_ci				 struct cdnsp_transfer_event *event)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	const struct usb_endpoint_descriptor *desc;
122962306a36Sopenharmony_ci	bool handling_skipped_tds = false;
123062306a36Sopenharmony_ci	struct cdnsp_segment *ep_seg;
123162306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
123262306a36Sopenharmony_ci	int status = -EINPROGRESS;
123362306a36Sopenharmony_ci	union cdnsp_trb *ep_trb;
123462306a36Sopenharmony_ci	dma_addr_t ep_trb_dma;
123562306a36Sopenharmony_ci	struct cdnsp_ep *pep;
123662306a36Sopenharmony_ci	struct cdnsp_td *td;
123762306a36Sopenharmony_ci	u32 trb_comp_code;
123862306a36Sopenharmony_ci	int invalidate;
123962306a36Sopenharmony_ci	int ep_index;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	invalidate = le32_to_cpu(event->flags) & TRB_EVENT_INVALIDATE;
124262306a36Sopenharmony_ci	ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
124362306a36Sopenharmony_ci	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
124462306a36Sopenharmony_ci	ep_trb_dma = le64_to_cpu(event->buffer);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	pep = &pdev->eps[ep_index];
124762306a36Sopenharmony_ci	ep_ring = cdnsp_dma_to_transfer_ring(pep, le64_to_cpu(event->buffer));
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/*
125062306a36Sopenharmony_ci	 * If device is disconnect then all requests will be dequeued
125162306a36Sopenharmony_ci	 * by upper layers as part of disconnect sequence.
125262306a36Sopenharmony_ci	 * We don't want handle such event to avoid racing.
125362306a36Sopenharmony_ci	 */
125462306a36Sopenharmony_ci	if (invalidate || !pdev->gadget.connected)
125562306a36Sopenharmony_ci		goto cleanup;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	if (GET_EP_CTX_STATE(pep->out_ctx) == EP_STATE_DISABLED) {
125862306a36Sopenharmony_ci		trace_cdnsp_ep_disabled(pep->out_ctx);
125962306a36Sopenharmony_ci		goto err_out;
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/* Some transfer events don't always point to a trb*/
126362306a36Sopenharmony_ci	if (!ep_ring) {
126462306a36Sopenharmony_ci		switch (trb_comp_code) {
126562306a36Sopenharmony_ci		case COMP_INVALID_STREAM_TYPE_ERROR:
126662306a36Sopenharmony_ci		case COMP_INVALID_STREAM_ID_ERROR:
126762306a36Sopenharmony_ci		case COMP_RING_UNDERRUN:
126862306a36Sopenharmony_ci		case COMP_RING_OVERRUN:
126962306a36Sopenharmony_ci			goto cleanup;
127062306a36Sopenharmony_ci		default:
127162306a36Sopenharmony_ci			dev_err(pdev->dev, "ERROR: %s event for unknown ring\n",
127262306a36Sopenharmony_ci				pep->name);
127362306a36Sopenharmony_ci			goto err_out;
127462306a36Sopenharmony_ci		}
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	/* Look for some error cases that need special treatment. */
127862306a36Sopenharmony_ci	switch (trb_comp_code) {
127962306a36Sopenharmony_ci	case COMP_BABBLE_DETECTED_ERROR:
128062306a36Sopenharmony_ci		status = -EOVERFLOW;
128162306a36Sopenharmony_ci		break;
128262306a36Sopenharmony_ci	case COMP_RING_UNDERRUN:
128362306a36Sopenharmony_ci	case COMP_RING_OVERRUN:
128462306a36Sopenharmony_ci		/*
128562306a36Sopenharmony_ci		 * When the Isoch ring is empty, the controller will generate
128662306a36Sopenharmony_ci		 * a Ring Overrun Event for IN Isoch endpoint or Ring
128762306a36Sopenharmony_ci		 * Underrun Event for OUT Isoch endpoint.
128862306a36Sopenharmony_ci		 */
128962306a36Sopenharmony_ci		goto cleanup;
129062306a36Sopenharmony_ci	case COMP_MISSED_SERVICE_ERROR:
129162306a36Sopenharmony_ci		/*
129262306a36Sopenharmony_ci		 * When encounter missed service error, one or more isoc tds
129362306a36Sopenharmony_ci		 * may be missed by controller.
129462306a36Sopenharmony_ci		 * Set skip flag of the ep_ring; Complete the missed tds as
129562306a36Sopenharmony_ci		 * short transfer when process the ep_ring next time.
129662306a36Sopenharmony_ci		 */
129762306a36Sopenharmony_ci		pep->skip = true;
129862306a36Sopenharmony_ci		break;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	do {
130262306a36Sopenharmony_ci		/*
130362306a36Sopenharmony_ci		 * This TRB should be in the TD at the head of this ring's TD
130462306a36Sopenharmony_ci		 * list.
130562306a36Sopenharmony_ci		 */
130662306a36Sopenharmony_ci		if (list_empty(&ep_ring->td_list)) {
130762306a36Sopenharmony_ci			/*
130862306a36Sopenharmony_ci			 * Don't print warnings if it's due to a stopped
130962306a36Sopenharmony_ci			 * endpoint generating an extra completion event, or
131062306a36Sopenharmony_ci			 * a event for the last TRB of a short TD we already
131162306a36Sopenharmony_ci			 * got a short event for.
131262306a36Sopenharmony_ci			 * The short TD is already removed from the TD list.
131362306a36Sopenharmony_ci			 */
131462306a36Sopenharmony_ci			if (!(trb_comp_code == COMP_STOPPED ||
131562306a36Sopenharmony_ci			      trb_comp_code == COMP_STOPPED_LENGTH_INVALID ||
131662306a36Sopenharmony_ci			      ep_ring->last_td_was_short))
131762306a36Sopenharmony_ci				trace_cdnsp_trb_without_td(ep_ring,
131862306a36Sopenharmony_ci					(struct cdnsp_generic_trb *)event);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci			if (pep->skip) {
132162306a36Sopenharmony_ci				pep->skip = false;
132262306a36Sopenharmony_ci				trace_cdnsp_ep_list_empty_with_skip(pep, 0);
132362306a36Sopenharmony_ci			}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci			goto cleanup;
132662306a36Sopenharmony_ci		}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci		td = list_entry(ep_ring->td_list.next, struct cdnsp_td,
132962306a36Sopenharmony_ci				td_list);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci		/* Is this a TRB in the currently executing TD? */
133262306a36Sopenharmony_ci		ep_seg = cdnsp_trb_in_td(pdev, ep_ring->deq_seg,
133362306a36Sopenharmony_ci					 ep_ring->dequeue, td->last_trb,
133462306a36Sopenharmony_ci					 ep_trb_dma);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		desc = td->preq->pep->endpoint.desc;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci		if (ep_seg) {
133962306a36Sopenharmony_ci			ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma)
134062306a36Sopenharmony_ci					       / sizeof(*ep_trb)];
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci			trace_cdnsp_handle_transfer(ep_ring,
134362306a36Sopenharmony_ci					(struct cdnsp_generic_trb *)ep_trb);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci			if (pep->skip && usb_endpoint_xfer_isoc(desc) &&
134662306a36Sopenharmony_ci			    td->last_trb != ep_trb)
134762306a36Sopenharmony_ci				return -EAGAIN;
134862306a36Sopenharmony_ci		}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci		/*
135162306a36Sopenharmony_ci		 * Skip the Force Stopped Event. The event_trb(ep_trb_dma)
135262306a36Sopenharmony_ci		 * of FSE is not in the current TD pointed by ep_ring->dequeue
135362306a36Sopenharmony_ci		 * because that the hardware dequeue pointer still at the
135462306a36Sopenharmony_ci		 * previous TRB of the current TD. The previous TRB maybe a
135562306a36Sopenharmony_ci		 * Link TD or the last TRB of the previous TD. The command
135662306a36Sopenharmony_ci		 * completion handle will take care the rest.
135762306a36Sopenharmony_ci		 */
135862306a36Sopenharmony_ci		if (!ep_seg && (trb_comp_code == COMP_STOPPED ||
135962306a36Sopenharmony_ci				trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) {
136062306a36Sopenharmony_ci			pep->skip = false;
136162306a36Sopenharmony_ci			goto cleanup;
136262306a36Sopenharmony_ci		}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci		if (!ep_seg) {
136562306a36Sopenharmony_ci			if (!pep->skip || !usb_endpoint_xfer_isoc(desc)) {
136662306a36Sopenharmony_ci				/* Something is busted, give up! */
136762306a36Sopenharmony_ci				dev_err(pdev->dev,
136862306a36Sopenharmony_ci					"ERROR Transfer event TRB DMA ptr not "
136962306a36Sopenharmony_ci					"part of current TD ep_index %d "
137062306a36Sopenharmony_ci					"comp_code %u\n", ep_index,
137162306a36Sopenharmony_ci					trb_comp_code);
137262306a36Sopenharmony_ci				return -EINVAL;
137362306a36Sopenharmony_ci			}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci			cdnsp_skip_isoc_td(pdev, td, event, pep, status);
137662306a36Sopenharmony_ci			goto cleanup;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci		if (trb_comp_code == COMP_SHORT_PACKET)
138062306a36Sopenharmony_ci			ep_ring->last_td_was_short = true;
138162306a36Sopenharmony_ci		else
138262306a36Sopenharmony_ci			ep_ring->last_td_was_short = false;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci		if (pep->skip) {
138562306a36Sopenharmony_ci			pep->skip = false;
138662306a36Sopenharmony_ci			cdnsp_skip_isoc_td(pdev, td, event, pep, status);
138762306a36Sopenharmony_ci			goto cleanup;
138862306a36Sopenharmony_ci		}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci		if (cdnsp_trb_is_noop(ep_trb))
139162306a36Sopenharmony_ci			goto cleanup;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		if (usb_endpoint_xfer_control(desc))
139462306a36Sopenharmony_ci			cdnsp_process_ctrl_td(pdev, td, ep_trb, event, pep,
139562306a36Sopenharmony_ci					      &status);
139662306a36Sopenharmony_ci		else if (usb_endpoint_xfer_isoc(desc))
139762306a36Sopenharmony_ci			cdnsp_process_isoc_td(pdev, td, ep_trb, event, pep,
139862306a36Sopenharmony_ci					      status);
139962306a36Sopenharmony_ci		else
140062306a36Sopenharmony_ci			cdnsp_process_bulk_intr_td(pdev, td, ep_trb, event, pep,
140162306a36Sopenharmony_ci						   &status);
140262306a36Sopenharmony_cicleanup:
140362306a36Sopenharmony_ci		handling_skipped_tds = pep->skip;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		/*
140662306a36Sopenharmony_ci		 * Do not update event ring dequeue pointer if we're in a loop
140762306a36Sopenharmony_ci		 * processing missed tds.
140862306a36Sopenharmony_ci		 */
140962306a36Sopenharmony_ci		if (!handling_skipped_tds)
141062306a36Sopenharmony_ci			cdnsp_inc_deq(pdev, pdev->event_ring);
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/*
141362306a36Sopenharmony_ci	 * If ep->skip is set, it means there are missed tds on the
141462306a36Sopenharmony_ci	 * endpoint ring need to take care of.
141562306a36Sopenharmony_ci	 * Process them as short transfer until reach the td pointed by
141662306a36Sopenharmony_ci	 * the event.
141762306a36Sopenharmony_ci	 */
141862306a36Sopenharmony_ci	} while (handling_skipped_tds);
141962306a36Sopenharmony_ci	return 0;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cierr_out:
142262306a36Sopenharmony_ci	dev_err(pdev->dev, "@%016llx %08x %08x %08x %08x\n",
142362306a36Sopenharmony_ci		(unsigned long long)
142462306a36Sopenharmony_ci		cdnsp_trb_virt_to_dma(pdev->event_ring->deq_seg,
142562306a36Sopenharmony_ci				      pdev->event_ring->dequeue),
142662306a36Sopenharmony_ci		 lower_32_bits(le64_to_cpu(event->buffer)),
142762306a36Sopenharmony_ci		 upper_32_bits(le64_to_cpu(event->buffer)),
142862306a36Sopenharmony_ci		 le32_to_cpu(event->transfer_len),
142962306a36Sopenharmony_ci		 le32_to_cpu(event->flags));
143062306a36Sopenharmony_ci	return -EINVAL;
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci/*
143462306a36Sopenharmony_ci * This function handles all events on the event ring.
143562306a36Sopenharmony_ci * Returns true for "possibly more events to process" (caller should call
143662306a36Sopenharmony_ci * again), otherwise false if done.
143762306a36Sopenharmony_ci */
143862306a36Sopenharmony_cistatic bool cdnsp_handle_event(struct cdnsp_device *pdev)
143962306a36Sopenharmony_ci{
144062306a36Sopenharmony_ci	unsigned int comp_code;
144162306a36Sopenharmony_ci	union cdnsp_trb *event;
144262306a36Sopenharmony_ci	bool update_ptrs = true;
144362306a36Sopenharmony_ci	u32 cycle_bit;
144462306a36Sopenharmony_ci	int ret = 0;
144562306a36Sopenharmony_ci	u32 flags;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	event = pdev->event_ring->dequeue;
144862306a36Sopenharmony_ci	flags = le32_to_cpu(event->event_cmd.flags);
144962306a36Sopenharmony_ci	cycle_bit = (flags & TRB_CYCLE);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	/* Does the controller or driver own the TRB? */
145262306a36Sopenharmony_ci	if (cycle_bit != pdev->event_ring->cycle_state)
145362306a36Sopenharmony_ci		return false;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	trace_cdnsp_handle_event(pdev->event_ring, &event->generic);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	/*
145862306a36Sopenharmony_ci	 * Barrier between reading the TRB_CYCLE (valid) flag above and any
145962306a36Sopenharmony_ci	 * reads of the event's flags/data below.
146062306a36Sopenharmony_ci	 */
146162306a36Sopenharmony_ci	rmb();
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	switch (flags & TRB_TYPE_BITMASK) {
146462306a36Sopenharmony_ci	case TRB_TYPE(TRB_COMPLETION):
146562306a36Sopenharmony_ci		/*
146662306a36Sopenharmony_ci		 * Command can't be handled in interrupt context so just
146762306a36Sopenharmony_ci		 * increment command ring dequeue pointer.
146862306a36Sopenharmony_ci		 */
146962306a36Sopenharmony_ci		cdnsp_inc_deq(pdev, pdev->cmd_ring);
147062306a36Sopenharmony_ci		break;
147162306a36Sopenharmony_ci	case TRB_TYPE(TRB_PORT_STATUS):
147262306a36Sopenharmony_ci		cdnsp_handle_port_status(pdev, event);
147362306a36Sopenharmony_ci		update_ptrs = false;
147462306a36Sopenharmony_ci		break;
147562306a36Sopenharmony_ci	case TRB_TYPE(TRB_TRANSFER):
147662306a36Sopenharmony_ci		ret = cdnsp_handle_tx_event(pdev, &event->trans_event);
147762306a36Sopenharmony_ci		if (ret >= 0)
147862306a36Sopenharmony_ci			update_ptrs = false;
147962306a36Sopenharmony_ci		break;
148062306a36Sopenharmony_ci	case TRB_TYPE(TRB_SETUP):
148162306a36Sopenharmony_ci		pdev->ep0_stage = CDNSP_SETUP_STAGE;
148262306a36Sopenharmony_ci		pdev->setup_id = TRB_SETUPID_TO_TYPE(flags);
148362306a36Sopenharmony_ci		pdev->setup_speed = TRB_SETUP_SPEEDID(flags);
148462306a36Sopenharmony_ci		pdev->setup = *((struct usb_ctrlrequest *)
148562306a36Sopenharmony_ci				&event->trans_event.buffer);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		cdnsp_setup_analyze(pdev);
148862306a36Sopenharmony_ci		break;
148962306a36Sopenharmony_ci	case TRB_TYPE(TRB_ENDPOINT_NRDY):
149062306a36Sopenharmony_ci		cdnsp_handle_tx_nrdy(pdev, &event->trans_event);
149162306a36Sopenharmony_ci		break;
149262306a36Sopenharmony_ci	case TRB_TYPE(TRB_HC_EVENT): {
149362306a36Sopenharmony_ci		comp_code = GET_COMP_CODE(le32_to_cpu(event->generic.field[2]));
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci		switch (comp_code) {
149662306a36Sopenharmony_ci		case COMP_EVENT_RING_FULL_ERROR:
149762306a36Sopenharmony_ci			dev_err(pdev->dev, "Event Ring Full\n");
149862306a36Sopenharmony_ci			break;
149962306a36Sopenharmony_ci		default:
150062306a36Sopenharmony_ci			dev_err(pdev->dev, "Controller error code 0x%02x\n",
150162306a36Sopenharmony_ci				comp_code);
150262306a36Sopenharmony_ci		}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci		break;
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ci	case TRB_TYPE(TRB_MFINDEX_WRAP):
150762306a36Sopenharmony_ci	case TRB_TYPE(TRB_DRB_OVERFLOW):
150862306a36Sopenharmony_ci		break;
150962306a36Sopenharmony_ci	default:
151062306a36Sopenharmony_ci		dev_warn(pdev->dev, "ERROR unknown event type %ld\n",
151162306a36Sopenharmony_ci			 TRB_FIELD_TO_TYPE(flags));
151262306a36Sopenharmony_ci	}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	if (update_ptrs)
151562306a36Sopenharmony_ci		/* Update SW event ring dequeue pointer. */
151662306a36Sopenharmony_ci		cdnsp_inc_deq(pdev, pdev->event_ring);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	/*
151962306a36Sopenharmony_ci	 * Caller will call us again to check if there are more items
152062306a36Sopenharmony_ci	 * on the event ring.
152162306a36Sopenharmony_ci	 */
152262306a36Sopenharmony_ci	return true;
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ciirqreturn_t cdnsp_thread_irq_handler(int irq, void *data)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	struct cdnsp_device *pdev = (struct cdnsp_device *)data;
152862306a36Sopenharmony_ci	union cdnsp_trb *event_ring_deq;
152962306a36Sopenharmony_ci	unsigned long flags;
153062306a36Sopenharmony_ci	int counter = 0;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	local_bh_disable();
153362306a36Sopenharmony_ci	spin_lock_irqsave(&pdev->lock, flags);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (pdev->cdnsp_state & (CDNSP_STATE_HALTED | CDNSP_STATE_DYING)) {
153662306a36Sopenharmony_ci		/*
153762306a36Sopenharmony_ci		 * While removing or stopping driver there may still be deferred
153862306a36Sopenharmony_ci		 * not handled interrupt which should not be treated as error.
153962306a36Sopenharmony_ci		 * Driver should simply ignore it.
154062306a36Sopenharmony_ci		 */
154162306a36Sopenharmony_ci		if (pdev->gadget_driver)
154262306a36Sopenharmony_ci			cdnsp_died(pdev);
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		spin_unlock_irqrestore(&pdev->lock, flags);
154562306a36Sopenharmony_ci		local_bh_enable();
154662306a36Sopenharmony_ci		return IRQ_HANDLED;
154762306a36Sopenharmony_ci	}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	event_ring_deq = pdev->event_ring->dequeue;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	while (cdnsp_handle_event(pdev)) {
155262306a36Sopenharmony_ci		if (++counter >= TRBS_PER_EV_DEQ_UPDATE) {
155362306a36Sopenharmony_ci			cdnsp_update_erst_dequeue(pdev, event_ring_deq, 0);
155462306a36Sopenharmony_ci			event_ring_deq = pdev->event_ring->dequeue;
155562306a36Sopenharmony_ci			counter = 0;
155662306a36Sopenharmony_ci		}
155762306a36Sopenharmony_ci	}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	cdnsp_update_erst_dequeue(pdev, event_ring_deq, 1);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdev->lock, flags);
156262306a36Sopenharmony_ci	local_bh_enable();
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	return IRQ_HANDLED;
156562306a36Sopenharmony_ci}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ciirqreturn_t cdnsp_irq_handler(int irq, void *priv)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	struct cdnsp_device *pdev = (struct cdnsp_device *)priv;
157062306a36Sopenharmony_ci	u32 irq_pending;
157162306a36Sopenharmony_ci	u32 status;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	status = readl(&pdev->op_regs->status);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (status == ~(u32)0) {
157662306a36Sopenharmony_ci		cdnsp_died(pdev);
157762306a36Sopenharmony_ci		return IRQ_HANDLED;
157862306a36Sopenharmony_ci	}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	if (!(status & STS_EINT))
158162306a36Sopenharmony_ci		return IRQ_NONE;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	writel(status | STS_EINT, &pdev->op_regs->status);
158462306a36Sopenharmony_ci	irq_pending = readl(&pdev->ir_set->irq_pending);
158562306a36Sopenharmony_ci	irq_pending |= IMAN_IP;
158662306a36Sopenharmony_ci	writel(irq_pending, &pdev->ir_set->irq_pending);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (status & STS_FATAL) {
158962306a36Sopenharmony_ci		cdnsp_died(pdev);
159062306a36Sopenharmony_ci		return IRQ_HANDLED;
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	return IRQ_WAKE_THREAD;
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci/*
159762306a36Sopenharmony_ci * Generic function for queuing a TRB on a ring.
159862306a36Sopenharmony_ci * The caller must have checked to make sure there's room on the ring.
159962306a36Sopenharmony_ci *
160062306a36Sopenharmony_ci * @more_trbs_coming:	Will you enqueue more TRBs before setting doorbell?
160162306a36Sopenharmony_ci */
160262306a36Sopenharmony_cistatic void cdnsp_queue_trb(struct cdnsp_device *pdev, struct cdnsp_ring *ring,
160362306a36Sopenharmony_ci			    bool more_trbs_coming, u32 field1, u32 field2,
160462306a36Sopenharmony_ci			    u32 field3, u32 field4)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	struct cdnsp_generic_trb *trb;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	trb = &ring->enqueue->generic;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	trb->field[0] = cpu_to_le32(field1);
161162306a36Sopenharmony_ci	trb->field[1] = cpu_to_le32(field2);
161262306a36Sopenharmony_ci	trb->field[2] = cpu_to_le32(field3);
161362306a36Sopenharmony_ci	trb->field[3] = cpu_to_le32(field4);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	trace_cdnsp_queue_trb(ring, trb);
161662306a36Sopenharmony_ci	cdnsp_inc_enq(pdev, ring, more_trbs_coming);
161762306a36Sopenharmony_ci}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci/*
162062306a36Sopenharmony_ci * Does various checks on the endpoint ring, and makes it ready to
162162306a36Sopenharmony_ci * queue num_trbs.
162262306a36Sopenharmony_ci */
162362306a36Sopenharmony_cistatic int cdnsp_prepare_ring(struct cdnsp_device *pdev,
162462306a36Sopenharmony_ci			      struct cdnsp_ring *ep_ring,
162562306a36Sopenharmony_ci			      u32 ep_state, unsigned
162662306a36Sopenharmony_ci			      int num_trbs,
162762306a36Sopenharmony_ci			      gfp_t mem_flags)
162862306a36Sopenharmony_ci{
162962306a36Sopenharmony_ci	unsigned int num_trbs_needed;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	/* Make sure the endpoint has been added to controller schedule. */
163262306a36Sopenharmony_ci	switch (ep_state) {
163362306a36Sopenharmony_ci	case EP_STATE_STOPPED:
163462306a36Sopenharmony_ci	case EP_STATE_RUNNING:
163562306a36Sopenharmony_ci	case EP_STATE_HALTED:
163662306a36Sopenharmony_ci		break;
163762306a36Sopenharmony_ci	default:
163862306a36Sopenharmony_ci		dev_err(pdev->dev, "ERROR: incorrect endpoint state\n");
163962306a36Sopenharmony_ci		return -EINVAL;
164062306a36Sopenharmony_ci	}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	while (1) {
164362306a36Sopenharmony_ci		if (cdnsp_room_on_ring(pdev, ep_ring, num_trbs))
164462306a36Sopenharmony_ci			break;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci		trace_cdnsp_no_room_on_ring("try ring expansion");
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci		num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
164962306a36Sopenharmony_ci		if (cdnsp_ring_expansion(pdev, ep_ring, num_trbs_needed,
165062306a36Sopenharmony_ci					 mem_flags)) {
165162306a36Sopenharmony_ci			dev_err(pdev->dev, "Ring expansion failed\n");
165262306a36Sopenharmony_ci			return -ENOMEM;
165362306a36Sopenharmony_ci		}
165462306a36Sopenharmony_ci	}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	while (cdnsp_trb_is_link(ep_ring->enqueue)) {
165762306a36Sopenharmony_ci		ep_ring->enqueue->link.control |= cpu_to_le32(TRB_CHAIN);
165862306a36Sopenharmony_ci		/* The cycle bit must be set as the last operation. */
165962306a36Sopenharmony_ci		wmb();
166062306a36Sopenharmony_ci		ep_ring->enqueue->link.control ^= cpu_to_le32(TRB_CYCLE);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci		/* Toggle the cycle bit after the last ring segment. */
166362306a36Sopenharmony_ci		if (cdnsp_link_trb_toggles_cycle(ep_ring->enqueue))
166462306a36Sopenharmony_ci			ep_ring->cycle_state ^= 1;
166562306a36Sopenharmony_ci		ep_ring->enq_seg = ep_ring->enq_seg->next;
166662306a36Sopenharmony_ci		ep_ring->enqueue = ep_ring->enq_seg->trbs;
166762306a36Sopenharmony_ci	}
166862306a36Sopenharmony_ci	return 0;
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic int cdnsp_prepare_transfer(struct cdnsp_device *pdev,
167262306a36Sopenharmony_ci				  struct cdnsp_request *preq,
167362306a36Sopenharmony_ci				  unsigned int num_trbs)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
167662306a36Sopenharmony_ci	int ret;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	ep_ring = cdnsp_get_transfer_ring(pdev, preq->pep,
167962306a36Sopenharmony_ci					  preq->request.stream_id);
168062306a36Sopenharmony_ci	if (!ep_ring)
168162306a36Sopenharmony_ci		return -EINVAL;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	ret = cdnsp_prepare_ring(pdev, ep_ring,
168462306a36Sopenharmony_ci				 GET_EP_CTX_STATE(preq->pep->out_ctx),
168562306a36Sopenharmony_ci				 num_trbs, GFP_ATOMIC);
168662306a36Sopenharmony_ci	if (ret)
168762306a36Sopenharmony_ci		return ret;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	INIT_LIST_HEAD(&preq->td.td_list);
169062306a36Sopenharmony_ci	preq->td.preq = preq;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	/* Add this TD to the tail of the endpoint ring's TD list. */
169362306a36Sopenharmony_ci	list_add_tail(&preq->td.td_list, &ep_ring->td_list);
169462306a36Sopenharmony_ci	ep_ring->num_tds++;
169562306a36Sopenharmony_ci	preq->pep->stream_info.td_count++;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	preq->td.start_seg = ep_ring->enq_seg;
169862306a36Sopenharmony_ci	preq->td.first_trb = ep_ring->enqueue;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	return 0;
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cistatic unsigned int cdnsp_count_trbs(u64 addr, u64 len)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	unsigned int num_trbs;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	num_trbs = DIV_ROUND_UP(len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
170862306a36Sopenharmony_ci				TRB_MAX_BUFF_SIZE);
170962306a36Sopenharmony_ci	if (num_trbs == 0)
171062306a36Sopenharmony_ci		num_trbs++;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	return num_trbs;
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_cistatic unsigned int count_trbs_needed(struct cdnsp_request *preq)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	return cdnsp_count_trbs(preq->request.dma, preq->request.length);
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic unsigned int count_sg_trbs_needed(struct cdnsp_request *preq)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	unsigned int i, len, full_len, num_trbs = 0;
172362306a36Sopenharmony_ci	struct scatterlist *sg;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	full_len = preq->request.length;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	for_each_sg(preq->request.sg, sg, preq->request.num_sgs, i) {
172862306a36Sopenharmony_ci		len = sg_dma_len(sg);
172962306a36Sopenharmony_ci		num_trbs += cdnsp_count_trbs(sg_dma_address(sg), len);
173062306a36Sopenharmony_ci		len = min(len, full_len);
173162306a36Sopenharmony_ci		full_len -= len;
173262306a36Sopenharmony_ci		if (full_len == 0)
173362306a36Sopenharmony_ci			break;
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	return num_trbs;
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_cistatic void cdnsp_check_trb_math(struct cdnsp_request *preq, int running_total)
174062306a36Sopenharmony_ci{
174162306a36Sopenharmony_ci	if (running_total != preq->request.length)
174262306a36Sopenharmony_ci		dev_err(preq->pep->pdev->dev,
174362306a36Sopenharmony_ci			"%s - Miscalculated tx length, "
174462306a36Sopenharmony_ci			"queued %#x, asked for %#x (%d)\n",
174562306a36Sopenharmony_ci			preq->pep->name, running_total,
174662306a36Sopenharmony_ci			preq->request.length, preq->request.actual);
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci/*
175062306a36Sopenharmony_ci * TD size is the number of max packet sized packets remaining in the TD
175162306a36Sopenharmony_ci * (*not* including this TRB).
175262306a36Sopenharmony_ci *
175362306a36Sopenharmony_ci * Total TD packet count = total_packet_count =
175462306a36Sopenharmony_ci *     DIV_ROUND_UP(TD size in bytes / wMaxPacketSize)
175562306a36Sopenharmony_ci *
175662306a36Sopenharmony_ci * Packets transferred up to and including this TRB = packets_transferred =
175762306a36Sopenharmony_ci *     rounddown(total bytes transferred including this TRB / wMaxPacketSize)
175862306a36Sopenharmony_ci *
175962306a36Sopenharmony_ci * TD size = total_packet_count - packets_transferred
176062306a36Sopenharmony_ci *
176162306a36Sopenharmony_ci * It must fit in bits 21:17, so it can't be bigger than 31.
176262306a36Sopenharmony_ci * This is taken care of in the TRB_TD_SIZE() macro
176362306a36Sopenharmony_ci *
176462306a36Sopenharmony_ci * The last TRB in a TD must have the TD size set to zero.
176562306a36Sopenharmony_ci */
176662306a36Sopenharmony_cistatic u32 cdnsp_td_remainder(struct cdnsp_device *pdev,
176762306a36Sopenharmony_ci			      int transferred,
176862306a36Sopenharmony_ci			      int trb_buff_len,
176962306a36Sopenharmony_ci			      unsigned int td_total_len,
177062306a36Sopenharmony_ci			      struct cdnsp_request *preq,
177162306a36Sopenharmony_ci			      bool more_trbs_coming,
177262306a36Sopenharmony_ci			      bool zlp)
177362306a36Sopenharmony_ci{
177462306a36Sopenharmony_ci	u32 maxp, total_packet_count;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	/* Before ZLP driver needs set TD_SIZE = 1. */
177762306a36Sopenharmony_ci	if (zlp)
177862306a36Sopenharmony_ci		return 1;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	/* One TRB with a zero-length data packet. */
178162306a36Sopenharmony_ci	if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) ||
178262306a36Sopenharmony_ci	    trb_buff_len == td_total_len)
178362306a36Sopenharmony_ci		return 0;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	maxp = usb_endpoint_maxp(preq->pep->endpoint.desc);
178662306a36Sopenharmony_ci	total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	/* Queuing functions don't count the current TRB into transferred. */
178962306a36Sopenharmony_ci	return (total_packet_count - ((transferred + trb_buff_len) / maxp));
179062306a36Sopenharmony_ci}
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_cistatic int cdnsp_align_td(struct cdnsp_device *pdev,
179362306a36Sopenharmony_ci			  struct cdnsp_request *preq, u32 enqd_len,
179462306a36Sopenharmony_ci			  u32 *trb_buff_len, struct cdnsp_segment *seg)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	struct device *dev = pdev->dev;
179762306a36Sopenharmony_ci	unsigned int unalign;
179862306a36Sopenharmony_ci	unsigned int max_pkt;
179962306a36Sopenharmony_ci	u32 new_buff_len;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	max_pkt = usb_endpoint_maxp(preq->pep->endpoint.desc);
180262306a36Sopenharmony_ci	unalign = (enqd_len + *trb_buff_len) % max_pkt;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	/* We got lucky, last normal TRB data on segment is packet aligned. */
180562306a36Sopenharmony_ci	if (unalign == 0)
180662306a36Sopenharmony_ci		return 0;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	/* Is the last nornal TRB alignable by splitting it. */
180962306a36Sopenharmony_ci	if (*trb_buff_len > unalign) {
181062306a36Sopenharmony_ci		*trb_buff_len -= unalign;
181162306a36Sopenharmony_ci		trace_cdnsp_bounce_align_td_split(preq, *trb_buff_len,
181262306a36Sopenharmony_ci						  enqd_len, 0, unalign);
181362306a36Sopenharmony_ci		return 0;
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	/*
181762306a36Sopenharmony_ci	 * We want enqd_len + trb_buff_len to sum up to a number aligned to
181862306a36Sopenharmony_ci	 * number which is divisible by the endpoint's wMaxPacketSize. IOW:
181962306a36Sopenharmony_ci	 * (size of currently enqueued TRBs + remainder) % wMaxPacketSize == 0.
182062306a36Sopenharmony_ci	 */
182162306a36Sopenharmony_ci	new_buff_len = max_pkt - (enqd_len % max_pkt);
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	if (new_buff_len > (preq->request.length - enqd_len))
182462306a36Sopenharmony_ci		new_buff_len = (preq->request.length - enqd_len);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	/* Create a max max_pkt sized bounce buffer pointed to by last trb. */
182762306a36Sopenharmony_ci	if (preq->direction) {
182862306a36Sopenharmony_ci		sg_pcopy_to_buffer(preq->request.sg,
182962306a36Sopenharmony_ci				   preq->request.num_mapped_sgs,
183062306a36Sopenharmony_ci				   seg->bounce_buf, new_buff_len, enqd_len);
183162306a36Sopenharmony_ci		seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
183262306a36Sopenharmony_ci						 max_pkt, DMA_TO_DEVICE);
183362306a36Sopenharmony_ci	} else {
183462306a36Sopenharmony_ci		seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
183562306a36Sopenharmony_ci						 max_pkt, DMA_FROM_DEVICE);
183662306a36Sopenharmony_ci	}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	if (dma_mapping_error(dev, seg->bounce_dma)) {
183962306a36Sopenharmony_ci		/* Try without aligning.*/
184062306a36Sopenharmony_ci		dev_warn(pdev->dev,
184162306a36Sopenharmony_ci			 "Failed mapping bounce buffer, not aligning\n");
184262306a36Sopenharmony_ci		return 0;
184362306a36Sopenharmony_ci	}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	*trb_buff_len = new_buff_len;
184662306a36Sopenharmony_ci	seg->bounce_len = new_buff_len;
184762306a36Sopenharmony_ci	seg->bounce_offs = enqd_len;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	trace_cdnsp_bounce_map(preq, new_buff_len, enqd_len, seg->bounce_dma,
185062306a36Sopenharmony_ci			       unalign);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	/*
185362306a36Sopenharmony_ci	 * Bounce buffer successful aligned and seg->bounce_dma will be used
185462306a36Sopenharmony_ci	 * in transfer TRB as new transfer buffer address.
185562306a36Sopenharmony_ci	 */
185662306a36Sopenharmony_ci	return 1;
185762306a36Sopenharmony_ci}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ciint cdnsp_queue_bulk_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	unsigned int enqd_len, block_len, trb_buff_len, full_len;
186262306a36Sopenharmony_ci	unsigned int start_cycle, num_sgs = 0;
186362306a36Sopenharmony_ci	struct cdnsp_generic_trb *start_trb;
186462306a36Sopenharmony_ci	u32 field, length_field, remainder;
186562306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
186662306a36Sopenharmony_ci	bool more_trbs_coming = true;
186762306a36Sopenharmony_ci	bool need_zero_pkt = false;
186862306a36Sopenharmony_ci	bool zero_len_trb = false;
186962306a36Sopenharmony_ci	struct cdnsp_ring *ring;
187062306a36Sopenharmony_ci	bool first_trb = true;
187162306a36Sopenharmony_ci	unsigned int num_trbs;
187262306a36Sopenharmony_ci	struct cdnsp_ep *pep;
187362306a36Sopenharmony_ci	u64 addr, send_addr;
187462306a36Sopenharmony_ci	int sent_len, ret;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	ring = cdnsp_request_to_transfer_ring(pdev, preq);
187762306a36Sopenharmony_ci	if (!ring)
187862306a36Sopenharmony_ci		return -EINVAL;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	full_len = preq->request.length;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	if (preq->request.num_sgs) {
188362306a36Sopenharmony_ci		num_sgs = preq->request.num_sgs;
188462306a36Sopenharmony_ci		sg = preq->request.sg;
188562306a36Sopenharmony_ci		addr = (u64)sg_dma_address(sg);
188662306a36Sopenharmony_ci		block_len = sg_dma_len(sg);
188762306a36Sopenharmony_ci		num_trbs = count_sg_trbs_needed(preq);
188862306a36Sopenharmony_ci	} else {
188962306a36Sopenharmony_ci		num_trbs = count_trbs_needed(preq);
189062306a36Sopenharmony_ci		addr = (u64)preq->request.dma;
189162306a36Sopenharmony_ci		block_len = full_len;
189262306a36Sopenharmony_ci	}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	pep = preq->pep;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	/* Deal with request.zero - need one more td/trb. */
189762306a36Sopenharmony_ci	if (preq->request.zero && preq->request.length &&
189862306a36Sopenharmony_ci	    IS_ALIGNED(full_len, usb_endpoint_maxp(pep->endpoint.desc))) {
189962306a36Sopenharmony_ci		need_zero_pkt = true;
190062306a36Sopenharmony_ci		num_trbs++;
190162306a36Sopenharmony_ci	}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	ret = cdnsp_prepare_transfer(pdev, preq, num_trbs);
190462306a36Sopenharmony_ci	if (ret)
190562306a36Sopenharmony_ci		return ret;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	/*
190862306a36Sopenharmony_ci	 * Don't give the first TRB to the hardware (by toggling the cycle bit)
190962306a36Sopenharmony_ci	 * until we've finished creating all the other TRBs. The ring's cycle
191062306a36Sopenharmony_ci	 * state may change as we enqueue the other TRBs, so save it too.
191162306a36Sopenharmony_ci	 */
191262306a36Sopenharmony_ci	start_trb = &ring->enqueue->generic;
191362306a36Sopenharmony_ci	start_cycle = ring->cycle_state;
191462306a36Sopenharmony_ci	send_addr = addr;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	/* Queue the TRBs, even if they are zero-length */
191762306a36Sopenharmony_ci	for (enqd_len = 0; zero_len_trb || first_trb || enqd_len < full_len;
191862306a36Sopenharmony_ci	     enqd_len += trb_buff_len) {
191962306a36Sopenharmony_ci		field = TRB_TYPE(TRB_NORMAL);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci		/* TRB buffer should not cross 64KB boundaries */
192262306a36Sopenharmony_ci		trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
192362306a36Sopenharmony_ci		trb_buff_len = min(trb_buff_len, block_len);
192462306a36Sopenharmony_ci		if (enqd_len + trb_buff_len > full_len)
192562306a36Sopenharmony_ci			trb_buff_len = full_len - enqd_len;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci		/* Don't change the cycle bit of the first TRB until later */
192862306a36Sopenharmony_ci		if (first_trb) {
192962306a36Sopenharmony_ci			first_trb = false;
193062306a36Sopenharmony_ci			if (start_cycle == 0)
193162306a36Sopenharmony_ci				field |= TRB_CYCLE;
193262306a36Sopenharmony_ci		} else {
193362306a36Sopenharmony_ci			field |= ring->cycle_state;
193462306a36Sopenharmony_ci		}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		/*
193762306a36Sopenharmony_ci		 * Chain all the TRBs together; clear the chain bit in the last
193862306a36Sopenharmony_ci		 * TRB to indicate it's the last TRB in the chain.
193962306a36Sopenharmony_ci		 */
194062306a36Sopenharmony_ci		if (enqd_len + trb_buff_len < full_len || need_zero_pkt) {
194162306a36Sopenharmony_ci			field |= TRB_CHAIN;
194262306a36Sopenharmony_ci			if (cdnsp_trb_is_link(ring->enqueue + 1)) {
194362306a36Sopenharmony_ci				if (cdnsp_align_td(pdev, preq, enqd_len,
194462306a36Sopenharmony_ci						   &trb_buff_len,
194562306a36Sopenharmony_ci						   ring->enq_seg)) {
194662306a36Sopenharmony_ci					send_addr = ring->enq_seg->bounce_dma;
194762306a36Sopenharmony_ci					/* Assuming TD won't span 2 segs */
194862306a36Sopenharmony_ci					preq->td.bounce_seg = ring->enq_seg;
194962306a36Sopenharmony_ci				}
195062306a36Sopenharmony_ci			}
195162306a36Sopenharmony_ci		}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci		if (enqd_len + trb_buff_len >= full_len) {
195462306a36Sopenharmony_ci			if (need_zero_pkt && !zero_len_trb) {
195562306a36Sopenharmony_ci				zero_len_trb = true;
195662306a36Sopenharmony_ci			} else {
195762306a36Sopenharmony_ci				zero_len_trb = false;
195862306a36Sopenharmony_ci				field &= ~TRB_CHAIN;
195962306a36Sopenharmony_ci				field |= TRB_IOC;
196062306a36Sopenharmony_ci				more_trbs_coming = false;
196162306a36Sopenharmony_ci				need_zero_pkt = false;
196262306a36Sopenharmony_ci				preq->td.last_trb = ring->enqueue;
196362306a36Sopenharmony_ci			}
196462306a36Sopenharmony_ci		}
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci		/* Only set interrupt on short packet for OUT endpoints. */
196762306a36Sopenharmony_ci		if (!preq->direction)
196862306a36Sopenharmony_ci			field |= TRB_ISP;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		/* Set the TRB length, TD size, and interrupter fields. */
197162306a36Sopenharmony_ci		remainder = cdnsp_td_remainder(pdev, enqd_len, trb_buff_len,
197262306a36Sopenharmony_ci					       full_len, preq,
197362306a36Sopenharmony_ci					       more_trbs_coming,
197462306a36Sopenharmony_ci					       zero_len_trb);
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci		length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) |
197762306a36Sopenharmony_ci			TRB_INTR_TARGET(0);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci		cdnsp_queue_trb(pdev, ring, more_trbs_coming,
198062306a36Sopenharmony_ci				lower_32_bits(send_addr),
198162306a36Sopenharmony_ci				upper_32_bits(send_addr),
198262306a36Sopenharmony_ci				length_field,
198362306a36Sopenharmony_ci				field);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		addr += trb_buff_len;
198662306a36Sopenharmony_ci		sent_len = trb_buff_len;
198762306a36Sopenharmony_ci		while (sg && sent_len >= block_len) {
198862306a36Sopenharmony_ci			/* New sg entry */
198962306a36Sopenharmony_ci			--num_sgs;
199062306a36Sopenharmony_ci			sent_len -= block_len;
199162306a36Sopenharmony_ci			if (num_sgs != 0) {
199262306a36Sopenharmony_ci				sg = sg_next(sg);
199362306a36Sopenharmony_ci				block_len = sg_dma_len(sg);
199462306a36Sopenharmony_ci				addr = (u64)sg_dma_address(sg);
199562306a36Sopenharmony_ci				addr += sent_len;
199662306a36Sopenharmony_ci			}
199762306a36Sopenharmony_ci		}
199862306a36Sopenharmony_ci		block_len -= sent_len;
199962306a36Sopenharmony_ci		send_addr = addr;
200062306a36Sopenharmony_ci	}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	cdnsp_check_trb_math(preq, enqd_len);
200362306a36Sopenharmony_ci	ret = cdnsp_giveback_first_trb(pdev, pep, preq->request.stream_id,
200462306a36Sopenharmony_ci				       start_cycle, start_trb);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	if (ret)
200762306a36Sopenharmony_ci		preq->td.drbl = 1;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	return 0;
201062306a36Sopenharmony_ci}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ciint cdnsp_queue_ctrl_tx(struct cdnsp_device *pdev, struct cdnsp_request *preq)
201362306a36Sopenharmony_ci{
201462306a36Sopenharmony_ci	u32 field, length_field, zlp = 0;
201562306a36Sopenharmony_ci	struct cdnsp_ep *pep = preq->pep;
201662306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
201762306a36Sopenharmony_ci	int num_trbs;
201862306a36Sopenharmony_ci	u32 maxp;
201962306a36Sopenharmony_ci	int ret;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	ep_ring = cdnsp_request_to_transfer_ring(pdev, preq);
202262306a36Sopenharmony_ci	if (!ep_ring)
202362306a36Sopenharmony_ci		return -EINVAL;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	/* 1 TRB for data, 1 for status */
202662306a36Sopenharmony_ci	num_trbs = (pdev->three_stage_setup) ? 2 : 1;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	maxp = usb_endpoint_maxp(pep->endpoint.desc);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	if (preq->request.zero && preq->request.length &&
203162306a36Sopenharmony_ci	    (preq->request.length % maxp == 0)) {
203262306a36Sopenharmony_ci		num_trbs++;
203362306a36Sopenharmony_ci		zlp = 1;
203462306a36Sopenharmony_ci	}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	ret = cdnsp_prepare_transfer(pdev, preq, num_trbs);
203762306a36Sopenharmony_ci	if (ret)
203862306a36Sopenharmony_ci		return ret;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	/* If there's data, queue data TRBs */
204162306a36Sopenharmony_ci	if (preq->request.length > 0) {
204262306a36Sopenharmony_ci		field = TRB_TYPE(TRB_DATA);
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci		if (zlp)
204562306a36Sopenharmony_ci			field |= TRB_CHAIN;
204662306a36Sopenharmony_ci		else
204762306a36Sopenharmony_ci			field |= TRB_IOC | (pdev->ep0_expect_in ? 0 : TRB_ISP);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci		if (pdev->ep0_expect_in)
205062306a36Sopenharmony_ci			field |= TRB_DIR_IN;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci		length_field = TRB_LEN(preq->request.length) |
205362306a36Sopenharmony_ci			       TRB_TD_SIZE(zlp) | TRB_INTR_TARGET(0);
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci		cdnsp_queue_trb(pdev, ep_ring, true,
205662306a36Sopenharmony_ci				lower_32_bits(preq->request.dma),
205762306a36Sopenharmony_ci				upper_32_bits(preq->request.dma), length_field,
205862306a36Sopenharmony_ci				field | ep_ring->cycle_state |
205962306a36Sopenharmony_ci				TRB_SETUPID(pdev->setup_id) |
206062306a36Sopenharmony_ci				pdev->setup_speed);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci		if (zlp) {
206362306a36Sopenharmony_ci			field = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci			if (!pdev->ep0_expect_in)
206662306a36Sopenharmony_ci				field = TRB_ISP;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci			cdnsp_queue_trb(pdev, ep_ring, true,
206962306a36Sopenharmony_ci					lower_32_bits(preq->request.dma),
207062306a36Sopenharmony_ci					upper_32_bits(preq->request.dma), 0,
207162306a36Sopenharmony_ci					field | ep_ring->cycle_state |
207262306a36Sopenharmony_ci					TRB_SETUPID(pdev->setup_id) |
207362306a36Sopenharmony_ci					pdev->setup_speed);
207462306a36Sopenharmony_ci		}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci		pdev->ep0_stage = CDNSP_DATA_STAGE;
207762306a36Sopenharmony_ci	}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	/* Save the DMA address of the last TRB in the TD. */
208062306a36Sopenharmony_ci	preq->td.last_trb = ep_ring->enqueue;
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	/* Queue status TRB. */
208362306a36Sopenharmony_ci	if (preq->request.length == 0)
208462306a36Sopenharmony_ci		field = ep_ring->cycle_state;
208562306a36Sopenharmony_ci	else
208662306a36Sopenharmony_ci		field = (ep_ring->cycle_state ^ 1);
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	if (preq->request.length > 0 && pdev->ep0_expect_in)
208962306a36Sopenharmony_ci		field |= TRB_DIR_IN;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	if (pep->ep_state & EP0_HALTED_STATUS) {
209262306a36Sopenharmony_ci		pep->ep_state &= ~EP0_HALTED_STATUS;
209362306a36Sopenharmony_ci		field |= TRB_SETUPSTAT(TRB_SETUPSTAT_STALL);
209462306a36Sopenharmony_ci	} else {
209562306a36Sopenharmony_ci		field |= TRB_SETUPSTAT(TRB_SETUPSTAT_ACK);
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	cdnsp_queue_trb(pdev, ep_ring, false, 0, 0, TRB_INTR_TARGET(0),
209962306a36Sopenharmony_ci			field | TRB_IOC | TRB_SETUPID(pdev->setup_id) |
210062306a36Sopenharmony_ci			TRB_TYPE(TRB_STATUS) | pdev->setup_speed);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	cdnsp_ring_ep_doorbell(pdev, pep, preq->request.stream_id);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	return 0;
210562306a36Sopenharmony_ci}
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ciint cdnsp_cmd_stop_ep(struct cdnsp_device *pdev, struct cdnsp_ep *pep)
210862306a36Sopenharmony_ci{
210962306a36Sopenharmony_ci	u32 ep_state = GET_EP_CTX_STATE(pep->out_ctx);
211062306a36Sopenharmony_ci	int ret = 0;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	if (ep_state == EP_STATE_STOPPED || ep_state == EP_STATE_DISABLED ||
211362306a36Sopenharmony_ci	    ep_state == EP_STATE_HALTED) {
211462306a36Sopenharmony_ci		trace_cdnsp_ep_stopped_or_disabled(pep->out_ctx);
211562306a36Sopenharmony_ci		goto ep_stopped;
211662306a36Sopenharmony_ci	}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	cdnsp_queue_stop_endpoint(pdev, pep->idx);
211962306a36Sopenharmony_ci	cdnsp_ring_cmd_db(pdev);
212062306a36Sopenharmony_ci	ret = cdnsp_wait_for_cmd_compl(pdev);
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	trace_cdnsp_handle_cmd_stop_ep(pep->out_ctx);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ciep_stopped:
212562306a36Sopenharmony_ci	pep->ep_state |= EP_STOPPED;
212662306a36Sopenharmony_ci	return ret;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ciint cdnsp_cmd_flush_ep(struct cdnsp_device *pdev, struct cdnsp_ep *pep)
213062306a36Sopenharmony_ci{
213162306a36Sopenharmony_ci	int ret;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	cdnsp_queue_flush_endpoint(pdev, pep->idx);
213462306a36Sopenharmony_ci	cdnsp_ring_cmd_db(pdev);
213562306a36Sopenharmony_ci	ret = cdnsp_wait_for_cmd_compl(pdev);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	trace_cdnsp_handle_cmd_flush_ep(pep->out_ctx);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	return ret;
214062306a36Sopenharmony_ci}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci/*
214362306a36Sopenharmony_ci * The transfer burst count field of the isochronous TRB defines the number of
214462306a36Sopenharmony_ci * bursts that are required to move all packets in this TD. Only SuperSpeed
214562306a36Sopenharmony_ci * devices can burst up to bMaxBurst number of packets per service interval.
214662306a36Sopenharmony_ci * This field is zero based, meaning a value of zero in the field means one
214762306a36Sopenharmony_ci * burst. Basically, for everything but SuperSpeed devices, this field will be
214862306a36Sopenharmony_ci * zero.
214962306a36Sopenharmony_ci */
215062306a36Sopenharmony_cistatic unsigned int cdnsp_get_burst_count(struct cdnsp_device *pdev,
215162306a36Sopenharmony_ci					  struct cdnsp_request *preq,
215262306a36Sopenharmony_ci					  unsigned int total_packet_count)
215362306a36Sopenharmony_ci{
215462306a36Sopenharmony_ci	unsigned int max_burst;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	if (pdev->gadget.speed < USB_SPEED_SUPER)
215762306a36Sopenharmony_ci		return 0;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	max_burst = preq->pep->endpoint.comp_desc->bMaxBurst;
216062306a36Sopenharmony_ci	return DIV_ROUND_UP(total_packet_count, max_burst + 1) - 1;
216162306a36Sopenharmony_ci}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci/*
216462306a36Sopenharmony_ci * Returns the number of packets in the last "burst" of packets. This field is
216562306a36Sopenharmony_ci * valid for all speeds of devices. USB 2.0 devices can only do one "burst", so
216662306a36Sopenharmony_ci * the last burst packet count is equal to the total number of packets in the
216762306a36Sopenharmony_ci * TD. SuperSpeed endpoints can have up to 3 bursts. All but the last burst
216862306a36Sopenharmony_ci * must contain (bMaxBurst + 1) number of packets, but the last burst can
216962306a36Sopenharmony_ci * contain 1 to (bMaxBurst + 1) packets.
217062306a36Sopenharmony_ci */
217162306a36Sopenharmony_cistatic unsigned int
217262306a36Sopenharmony_ci	cdnsp_get_last_burst_packet_count(struct cdnsp_device *pdev,
217362306a36Sopenharmony_ci					  struct cdnsp_request *preq,
217462306a36Sopenharmony_ci					  unsigned int total_packet_count)
217562306a36Sopenharmony_ci{
217662306a36Sopenharmony_ci	unsigned int max_burst;
217762306a36Sopenharmony_ci	unsigned int residue;
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	if (pdev->gadget.speed >= USB_SPEED_SUPER) {
218062306a36Sopenharmony_ci		/* bMaxBurst is zero based: 0 means 1 packet per burst. */
218162306a36Sopenharmony_ci		max_burst = preq->pep->endpoint.comp_desc->bMaxBurst;
218262306a36Sopenharmony_ci		residue = total_packet_count % (max_burst + 1);
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci		/*
218562306a36Sopenharmony_ci		 * If residue is zero, the last burst contains (max_burst + 1)
218662306a36Sopenharmony_ci		 * number of packets, but the TLBPC field is zero-based.
218762306a36Sopenharmony_ci		 */
218862306a36Sopenharmony_ci		if (residue == 0)
218962306a36Sopenharmony_ci			return max_burst;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci		return residue - 1;
219262306a36Sopenharmony_ci	}
219362306a36Sopenharmony_ci	if (total_packet_count == 0)
219462306a36Sopenharmony_ci		return 0;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	return total_packet_count - 1;
219762306a36Sopenharmony_ci}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci/* Queue function isoc transfer */
220062306a36Sopenharmony_ciint cdnsp_queue_isoc_tx(struct cdnsp_device *pdev,
220162306a36Sopenharmony_ci			struct cdnsp_request *preq)
220262306a36Sopenharmony_ci{
220362306a36Sopenharmony_ci	unsigned int trb_buff_len, td_len, td_remain_len, block_len;
220462306a36Sopenharmony_ci	unsigned int burst_count, last_burst_pkt;
220562306a36Sopenharmony_ci	unsigned int total_pkt_count, max_pkt;
220662306a36Sopenharmony_ci	struct cdnsp_generic_trb *start_trb;
220762306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
220862306a36Sopenharmony_ci	bool more_trbs_coming = true;
220962306a36Sopenharmony_ci	struct cdnsp_ring *ep_ring;
221062306a36Sopenharmony_ci	unsigned int num_sgs = 0;
221162306a36Sopenharmony_ci	int running_total = 0;
221262306a36Sopenharmony_ci	u32 field, length_field;
221362306a36Sopenharmony_ci	u64 addr, send_addr;
221462306a36Sopenharmony_ci	int start_cycle;
221562306a36Sopenharmony_ci	int trbs_per_td;
221662306a36Sopenharmony_ci	int i, sent_len, ret;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	ep_ring = preq->pep->ring;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	td_len = preq->request.length;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (preq->request.num_sgs) {
222362306a36Sopenharmony_ci		num_sgs = preq->request.num_sgs;
222462306a36Sopenharmony_ci		sg = preq->request.sg;
222562306a36Sopenharmony_ci		addr = (u64)sg_dma_address(sg);
222662306a36Sopenharmony_ci		block_len = sg_dma_len(sg);
222762306a36Sopenharmony_ci		trbs_per_td = count_sg_trbs_needed(preq);
222862306a36Sopenharmony_ci	} else {
222962306a36Sopenharmony_ci		addr = (u64)preq->request.dma;
223062306a36Sopenharmony_ci		block_len = td_len;
223162306a36Sopenharmony_ci		trbs_per_td = count_trbs_needed(preq);
223262306a36Sopenharmony_ci	}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	ret = cdnsp_prepare_transfer(pdev, preq, trbs_per_td);
223562306a36Sopenharmony_ci	if (ret)
223662306a36Sopenharmony_ci		return ret;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	start_trb = &ep_ring->enqueue->generic;
223962306a36Sopenharmony_ci	start_cycle = ep_ring->cycle_state;
224062306a36Sopenharmony_ci	td_remain_len = td_len;
224162306a36Sopenharmony_ci	send_addr = addr;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	max_pkt = usb_endpoint_maxp(preq->pep->endpoint.desc);
224462306a36Sopenharmony_ci	total_pkt_count = DIV_ROUND_UP(td_len, max_pkt);
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	/* A zero-length transfer still involves at least one packet. */
224762306a36Sopenharmony_ci	if (total_pkt_count == 0)
224862306a36Sopenharmony_ci		total_pkt_count++;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	burst_count = cdnsp_get_burst_count(pdev, preq, total_pkt_count);
225162306a36Sopenharmony_ci	last_burst_pkt = cdnsp_get_last_burst_packet_count(pdev, preq,
225262306a36Sopenharmony_ci							   total_pkt_count);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	/*
225562306a36Sopenharmony_ci	 * Set isoc specific data for the first TRB in a TD.
225662306a36Sopenharmony_ci	 * Prevent HW from getting the TRBs by keeping the cycle state
225762306a36Sopenharmony_ci	 * inverted in the first TDs isoc TRB.
225862306a36Sopenharmony_ci	 */
225962306a36Sopenharmony_ci	field = TRB_TYPE(TRB_ISOC) | TRB_TLBPC(last_burst_pkt) |
226062306a36Sopenharmony_ci		TRB_SIA | TRB_TBC(burst_count);
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	if (!start_cycle)
226362306a36Sopenharmony_ci		field |= TRB_CYCLE;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	/* Fill the rest of the TRB fields, and remaining normal TRBs. */
226662306a36Sopenharmony_ci	for (i = 0; i < trbs_per_td; i++) {
226762306a36Sopenharmony_ci		u32 remainder;
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci		/* Calculate TRB length. */
227062306a36Sopenharmony_ci		trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
227162306a36Sopenharmony_ci		trb_buff_len = min(trb_buff_len, block_len);
227262306a36Sopenharmony_ci		if (trb_buff_len > td_remain_len)
227362306a36Sopenharmony_ci			trb_buff_len = td_remain_len;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci		/* Set the TRB length, TD size, & interrupter fields. */
227662306a36Sopenharmony_ci		remainder = cdnsp_td_remainder(pdev, running_total,
227762306a36Sopenharmony_ci					       trb_buff_len, td_len, preq,
227862306a36Sopenharmony_ci					       more_trbs_coming, 0);
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci		length_field = TRB_LEN(trb_buff_len) | TRB_TD_SIZE(remainder) |
228162306a36Sopenharmony_ci			TRB_INTR_TARGET(0);
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci		/* Only first TRB is isoc, overwrite otherwise. */
228462306a36Sopenharmony_ci		if (i) {
228562306a36Sopenharmony_ci			field = TRB_TYPE(TRB_NORMAL) | ep_ring->cycle_state;
228662306a36Sopenharmony_ci			length_field |= TRB_TD_SIZE(remainder);
228762306a36Sopenharmony_ci		} else {
228862306a36Sopenharmony_ci			length_field |= TRB_TD_SIZE_TBC(burst_count);
228962306a36Sopenharmony_ci		}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci		/* Only set interrupt on short packet for OUT EPs. */
229262306a36Sopenharmony_ci		if (usb_endpoint_dir_out(preq->pep->endpoint.desc))
229362306a36Sopenharmony_ci			field |= TRB_ISP;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci		/* Set the chain bit for all except the last TRB. */
229662306a36Sopenharmony_ci		if (i < trbs_per_td - 1) {
229762306a36Sopenharmony_ci			more_trbs_coming = true;
229862306a36Sopenharmony_ci			field |= TRB_CHAIN;
229962306a36Sopenharmony_ci		} else {
230062306a36Sopenharmony_ci			more_trbs_coming = false;
230162306a36Sopenharmony_ci			preq->td.last_trb = ep_ring->enqueue;
230262306a36Sopenharmony_ci			field |= TRB_IOC;
230362306a36Sopenharmony_ci		}
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci		cdnsp_queue_trb(pdev, ep_ring, more_trbs_coming,
230662306a36Sopenharmony_ci				lower_32_bits(send_addr), upper_32_bits(send_addr),
230762306a36Sopenharmony_ci				length_field, field);
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci		running_total += trb_buff_len;
231062306a36Sopenharmony_ci		addr += trb_buff_len;
231162306a36Sopenharmony_ci		td_remain_len -= trb_buff_len;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci		sent_len = trb_buff_len;
231462306a36Sopenharmony_ci		while (sg && sent_len >= block_len) {
231562306a36Sopenharmony_ci			/* New sg entry */
231662306a36Sopenharmony_ci			--num_sgs;
231762306a36Sopenharmony_ci			sent_len -= block_len;
231862306a36Sopenharmony_ci			if (num_sgs != 0) {
231962306a36Sopenharmony_ci				sg = sg_next(sg);
232062306a36Sopenharmony_ci				block_len = sg_dma_len(sg);
232162306a36Sopenharmony_ci				addr = (u64)sg_dma_address(sg);
232262306a36Sopenharmony_ci				addr += sent_len;
232362306a36Sopenharmony_ci			}
232462306a36Sopenharmony_ci		}
232562306a36Sopenharmony_ci		block_len -= sent_len;
232662306a36Sopenharmony_ci		send_addr = addr;
232762306a36Sopenharmony_ci	}
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	/* Check TD length */
233062306a36Sopenharmony_ci	if (running_total != td_len) {
233162306a36Sopenharmony_ci		dev_err(pdev->dev, "ISOC TD length unmatch\n");
233262306a36Sopenharmony_ci		ret = -EINVAL;
233362306a36Sopenharmony_ci		goto cleanup;
233462306a36Sopenharmony_ci	}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	cdnsp_giveback_first_trb(pdev, preq->pep, preq->request.stream_id,
233762306a36Sopenharmony_ci				 start_cycle, start_trb);
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	return 0;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_cicleanup:
234262306a36Sopenharmony_ci	/* Clean up a partially enqueued isoc transfer. */
234362306a36Sopenharmony_ci	list_del_init(&preq->td.td_list);
234462306a36Sopenharmony_ci	ep_ring->num_tds--;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	/*
234762306a36Sopenharmony_ci	 * Use the first TD as a temporary variable to turn the TDs we've
234862306a36Sopenharmony_ci	 * queued into No-ops with a software-owned cycle bit.
234962306a36Sopenharmony_ci	 * That way the hardware won't accidentally start executing bogus TDs
235062306a36Sopenharmony_ci	 * when we partially overwrite them.
235162306a36Sopenharmony_ci	 * td->first_trb and td->start_seg are already set.
235262306a36Sopenharmony_ci	 */
235362306a36Sopenharmony_ci	preq->td.last_trb = ep_ring->enqueue;
235462306a36Sopenharmony_ci	/* Every TRB except the first & last will have its cycle bit flipped. */
235562306a36Sopenharmony_ci	cdnsp_td_to_noop(pdev, ep_ring, &preq->td, true);
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	/* Reset the ring enqueue back to the first TRB and its cycle bit. */
235862306a36Sopenharmony_ci	ep_ring->enqueue = preq->td.first_trb;
235962306a36Sopenharmony_ci	ep_ring->enq_seg = preq->td.start_seg;
236062306a36Sopenharmony_ci	ep_ring->cycle_state = start_cycle;
236162306a36Sopenharmony_ci	return ret;
236262306a36Sopenharmony_ci}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci/****		Command Ring Operations		****/
236562306a36Sopenharmony_ci/*
236662306a36Sopenharmony_ci * Generic function for queuing a command TRB on the command ring.
236762306a36Sopenharmony_ci * Driver queue only one command to ring in the moment.
236862306a36Sopenharmony_ci */
236962306a36Sopenharmony_cistatic void cdnsp_queue_command(struct cdnsp_device *pdev,
237062306a36Sopenharmony_ci				u32 field1,
237162306a36Sopenharmony_ci				u32 field2,
237262306a36Sopenharmony_ci				u32 field3,
237362306a36Sopenharmony_ci				u32 field4)
237462306a36Sopenharmony_ci{
237562306a36Sopenharmony_ci	cdnsp_prepare_ring(pdev, pdev->cmd_ring, EP_STATE_RUNNING, 1,
237662306a36Sopenharmony_ci			   GFP_ATOMIC);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	pdev->cmd.command_trb = pdev->cmd_ring->enqueue;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	cdnsp_queue_trb(pdev, pdev->cmd_ring, false, field1, field2,
238162306a36Sopenharmony_ci			field3, field4 | pdev->cmd_ring->cycle_state);
238262306a36Sopenharmony_ci}
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci/* Queue a slot enable or disable request on the command ring */
238562306a36Sopenharmony_civoid cdnsp_queue_slot_control(struct cdnsp_device *pdev, u32 trb_type)
238662306a36Sopenharmony_ci{
238762306a36Sopenharmony_ci	cdnsp_queue_command(pdev, 0, 0, 0, TRB_TYPE(trb_type) |
238862306a36Sopenharmony_ci			    SLOT_ID_FOR_TRB(pdev->slot_id));
238962306a36Sopenharmony_ci}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci/* Queue an address device command TRB */
239262306a36Sopenharmony_civoid cdnsp_queue_address_device(struct cdnsp_device *pdev,
239362306a36Sopenharmony_ci				dma_addr_t in_ctx_ptr,
239462306a36Sopenharmony_ci				enum cdnsp_setup_dev setup)
239562306a36Sopenharmony_ci{
239662306a36Sopenharmony_ci	cdnsp_queue_command(pdev, lower_32_bits(in_ctx_ptr),
239762306a36Sopenharmony_ci			    upper_32_bits(in_ctx_ptr), 0,
239862306a36Sopenharmony_ci			    TRB_TYPE(TRB_ADDR_DEV) |
239962306a36Sopenharmony_ci			    SLOT_ID_FOR_TRB(pdev->slot_id) |
240062306a36Sopenharmony_ci			    (setup == SETUP_CONTEXT_ONLY ? TRB_BSR : 0));
240162306a36Sopenharmony_ci}
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci/* Queue a reset device command TRB */
240462306a36Sopenharmony_civoid cdnsp_queue_reset_device(struct cdnsp_device *pdev)
240562306a36Sopenharmony_ci{
240662306a36Sopenharmony_ci	cdnsp_queue_command(pdev, 0, 0, 0, TRB_TYPE(TRB_RESET_DEV) |
240762306a36Sopenharmony_ci			    SLOT_ID_FOR_TRB(pdev->slot_id));
240862306a36Sopenharmony_ci}
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci/* Queue a configure endpoint command TRB */
241162306a36Sopenharmony_civoid cdnsp_queue_configure_endpoint(struct cdnsp_device *pdev,
241262306a36Sopenharmony_ci				    dma_addr_t in_ctx_ptr)
241362306a36Sopenharmony_ci{
241462306a36Sopenharmony_ci	cdnsp_queue_command(pdev, lower_32_bits(in_ctx_ptr),
241562306a36Sopenharmony_ci			    upper_32_bits(in_ctx_ptr), 0,
241662306a36Sopenharmony_ci			    TRB_TYPE(TRB_CONFIG_EP) |
241762306a36Sopenharmony_ci			    SLOT_ID_FOR_TRB(pdev->slot_id));
241862306a36Sopenharmony_ci}
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci/*
242162306a36Sopenharmony_ci * Suspend is set to indicate "Stop Endpoint Command" is being issued to stop
242262306a36Sopenharmony_ci * activity on an endpoint that is about to be suspended.
242362306a36Sopenharmony_ci */
242462306a36Sopenharmony_civoid cdnsp_queue_stop_endpoint(struct cdnsp_device *pdev, unsigned int ep_index)
242562306a36Sopenharmony_ci{
242662306a36Sopenharmony_ci	cdnsp_queue_command(pdev, 0, 0, 0, SLOT_ID_FOR_TRB(pdev->slot_id) |
242762306a36Sopenharmony_ci			    EP_ID_FOR_TRB(ep_index) | TRB_TYPE(TRB_STOP_RING));
242862306a36Sopenharmony_ci}
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci/* Set Transfer Ring Dequeue Pointer command. */
243162306a36Sopenharmony_civoid cdnsp_queue_new_dequeue_state(struct cdnsp_device *pdev,
243262306a36Sopenharmony_ci				   struct cdnsp_ep *pep,
243362306a36Sopenharmony_ci				   struct cdnsp_dequeue_state *deq_state)
243462306a36Sopenharmony_ci{
243562306a36Sopenharmony_ci	u32 trb_stream_id = STREAM_ID_FOR_TRB(deq_state->stream_id);
243662306a36Sopenharmony_ci	u32 trb_slot_id = SLOT_ID_FOR_TRB(pdev->slot_id);
243762306a36Sopenharmony_ci	u32 type = TRB_TYPE(TRB_SET_DEQ);
243862306a36Sopenharmony_ci	u32 trb_sct = 0;
243962306a36Sopenharmony_ci	dma_addr_t addr;
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	addr = cdnsp_trb_virt_to_dma(deq_state->new_deq_seg,
244262306a36Sopenharmony_ci				     deq_state->new_deq_ptr);
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	if (deq_state->stream_id)
244562306a36Sopenharmony_ci		trb_sct = SCT_FOR_TRB(SCT_PRI_TR);
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	cdnsp_queue_command(pdev, lower_32_bits(addr) | trb_sct |
244862306a36Sopenharmony_ci			    deq_state->new_cycle_state, upper_32_bits(addr),
244962306a36Sopenharmony_ci			    trb_stream_id, trb_slot_id |
245062306a36Sopenharmony_ci			    EP_ID_FOR_TRB(pep->idx) | type);
245162306a36Sopenharmony_ci}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_civoid cdnsp_queue_reset_ep(struct cdnsp_device *pdev, unsigned int ep_index)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	return cdnsp_queue_command(pdev, 0, 0, 0,
245662306a36Sopenharmony_ci				   SLOT_ID_FOR_TRB(pdev->slot_id) |
245762306a36Sopenharmony_ci				   EP_ID_FOR_TRB(ep_index) |
245862306a36Sopenharmony_ci				   TRB_TYPE(TRB_RESET_EP));
245962306a36Sopenharmony_ci}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci/*
246262306a36Sopenharmony_ci * Queue a halt endpoint request on the command ring.
246362306a36Sopenharmony_ci */
246462306a36Sopenharmony_civoid cdnsp_queue_halt_endpoint(struct cdnsp_device *pdev, unsigned int ep_index)
246562306a36Sopenharmony_ci{
246662306a36Sopenharmony_ci	cdnsp_queue_command(pdev, 0, 0, 0, TRB_TYPE(TRB_HALT_ENDPOINT) |
246762306a36Sopenharmony_ci			    SLOT_ID_FOR_TRB(pdev->slot_id) |
246862306a36Sopenharmony_ci			    EP_ID_FOR_TRB(ep_index));
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci/*
247262306a36Sopenharmony_ci * Queue a flush endpoint request on the command ring.
247362306a36Sopenharmony_ci */
247462306a36Sopenharmony_civoid  cdnsp_queue_flush_endpoint(struct cdnsp_device *pdev,
247562306a36Sopenharmony_ci				 unsigned int ep_index)
247662306a36Sopenharmony_ci{
247762306a36Sopenharmony_ci	cdnsp_queue_command(pdev, 0, 0, 0, TRB_TYPE(TRB_FLUSH_ENDPOINT) |
247862306a36Sopenharmony_ci			    SLOT_ID_FOR_TRB(pdev->slot_id) |
247962306a36Sopenharmony_ci			    EP_ID_FOR_TRB(ep_index));
248062306a36Sopenharmony_ci}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_civoid cdnsp_force_header_wakeup(struct cdnsp_device *pdev, int intf_num)
248362306a36Sopenharmony_ci{
248462306a36Sopenharmony_ci	u32 lo, mid;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	lo = TRB_FH_TO_PACKET_TYPE(TRB_FH_TR_PACKET) |
248762306a36Sopenharmony_ci	     TRB_FH_TO_DEVICE_ADDRESS(pdev->device_address);
248862306a36Sopenharmony_ci	mid = TRB_FH_TR_PACKET_DEV_NOT |
248962306a36Sopenharmony_ci	      TRB_FH_TO_NOT_TYPE(TRB_FH_TR_PACKET_FUNCTION_WAKE) |
249062306a36Sopenharmony_ci	      TRB_FH_TO_INTERFACE(intf_num);
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	cdnsp_queue_command(pdev, lo, mid, 0,
249362306a36Sopenharmony_ci			    TRB_TYPE(TRB_FORCE_HEADER) | SET_PORT_ID(2));
249462306a36Sopenharmony_ci}
2495