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