Skip to content

Commit

Permalink
usb: dwc3: gadget: prepare TRBs on update transfers too
Browse files Browse the repository at this point in the history
If we're updating transfers, we can also prepare as
many TRBs as we can fit in the ring. Let's start
doing that.

This patch 'solves' a limitation of how many TRBs we
can prepare when we're getting close the end of the
ring. Instead driver to prepare only up to end of
the ring, we check if we have space to wrap around
the ring properly.

Note that this only happens when our enqueue and
dequeue pointers are equal (which is the case for
bulk endpoints after an XferComplete event).

Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
  • Loading branch information
Felipe Balbi committed Jun 20, 2016
1 parent 7f370ed commit c423357
Showing 1 changed file with 29 additions and 21 deletions.
50 changes: 29 additions & 21 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -880,40 +880,48 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trace_dwc3_prepare_trb(dep, trb);
}

static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
{
struct dwc3_trb *tmp;

/*
* If enqueue & dequeue are equal than it is either full or empty.
*
* One way to know for sure is if the TRB right before us has HWO bit
* set or not. If it has, then we're definitely full and can't fit any
* more transfers in our ring.
*/
if (dep->trb_enqueue == dep->trb_dequeue) {
/* If we're full, enqueue/dequeue are > 0 */
if (dep->trb_enqueue) {
tmp = &dep->trb_pool[dep->trb_enqueue - 1];
if (tmp->ctrl & DWC3_TRB_CTRL_HWO)
return 0;
}

return DWC3_TRB_NUM - 1;
}

return dep->trb_dequeue - dep->trb_enqueue;
}

/*
* dwc3_prepare_trbs - setup TRBs from requests
* @dep: endpoint for which requests are being prepared
* @starting: true if the endpoint is idle and no requests are queued.
*
* The function goes through the requests list and sets up TRBs for the
* transfers. The function returns once there are no more TRBs available or
* it runs out of requests.
*/
static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
static void dwc3_prepare_trbs(struct dwc3_ep *dep)
{
struct dwc3_request *req, *n;
u32 trbs_left;
unsigned int last_one = 0;

BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);

trbs_left = dep->trb_dequeue - dep->trb_enqueue;

/*
* If enqueue & dequeue are equal than it is either full or empty. If we
* are starting to process requests then we are empty. Otherwise we are
* full and don't do anything
*/
if (!trbs_left) {
if (!starting)
return;

trbs_left = DWC3_TRB_NUM;
}

/* The last TRB is a link TRB, not used for xfer */
if (trbs_left <= 1)
return;
trbs_left = dwc3_calc_trbs_left(dep);

list_for_each_entry_safe(req, n, &dep->pending_list, list) {
unsigned length;
Expand Down Expand Up @@ -996,12 +1004,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
*/
if (start_new) {
if (list_empty(&dep->started_list))
dwc3_prepare_trbs(dep, start_new);
dwc3_prepare_trbs(dep);

/* req points to the first request which will be sent */
req = next_request(&dep->started_list);
} else {
dwc3_prepare_trbs(dep, start_new);
dwc3_prepare_trbs(dep);

/*
* req points to the first request where HWO changed from 0 to 1
Expand Down

0 comments on commit c423357

Please sign in to comment.