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

Commit 2d9edb28 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: dwc3: bulk out endpoint optimization"

parents 182931de 3585243d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
#include <linux/hrtimer.h>

#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -509,6 +510,7 @@ struct dwc3_ep_events {
 * @dbg_ep_events: different events counter for endpoint
 * @dbg_ep_events_diff: differential events counter for endpoint
 * @dbg_ep_events_ts: timestamp for previous event counters
 * @xfer_timer: timer to manage transfer complete event timeout
 */
struct dwc3_ep {
	struct usb_ep		endpoint;
@@ -548,6 +550,7 @@ struct dwc3_ep {
	struct dwc3_ep_events	dbg_ep_events;
	struct dwc3_ep_events	dbg_ep_events_diff;
	struct timespec		dbg_ep_events_ts;
	struct hrtimer		xfer_timer;
};

enum dwc3_phy {
+86 −2
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
#include <linux/list.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/module.h>

#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -58,6 +59,11 @@
#include "debug.h"
#include "io.h"

#define BULK_EP_XFER_TIMEOUT	(8)	/* milliseconds */

static int bulk_ep_xfer_timeout_ms = BULK_EP_XFER_TIMEOUT;
module_param(bulk_ep_xfer_timeout_ms, int, S_IRUGO | S_IWUSR);

static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend);
static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc);
@@ -69,6 +75,8 @@ struct dwc3_usb_gadget {
	struct dwc3 *dwc;
};

static void dwc3_endpoint_transfer_complete(struct dwc3 *, struct dwc3_ep *,
	const struct dwc3_event_depevt *, int);
/**
 * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
 * @dwc: pointer to our context structure
@@ -904,6 +912,17 @@ update_trb:
		break;

	case USB_ENDPOINT_XFER_BULK:
		trb->ctrl = DWC3_TRBCTL_NORMAL;
		/*
		 * bulk endpoint optimization: setting the CSP bit (continue on
		 * short packet) will prevent the core from generating an
		 * XferComplete event for each TRB with a short packet
		 * (except for the last TRB).
		 */
		if (!last)
			trb->ctrl |= DWC3_TRB_CTRL_CSP;
		break;

	case USB_ENDPOINT_XFER_INT:
		trb->ctrl = DWC3_TRBCTL_NORMAL;
		break;
@@ -1186,6 +1205,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
		dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
				dep->number);
		WARN_ON_ONCE(!dep->resource_index);

		if (usb_endpoint_xfer_bulk(dep->endpoint.desc)) {
			hrtimer_start(&dep->xfer_timer, ktime_set(0,
				bulk_ep_xfer_timeout_ms * NSEC_PER_MSEC),
				HRTIMER_MODE_REL);
		}
	}

	return 0;
@@ -2035,6 +2060,40 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {

/* -------------------------------------------------------------------------- */

static enum hrtimer_restart dwc3_gadget_ep_timer(struct hrtimer *hrtimer)
{
	struct dwc3_ep *dep = container_of(hrtimer, struct dwc3_ep, xfer_timer);
	struct dwc3_event_depevt event;
	struct dwc3 *dwc;

	if (!dep) {
		pr_err("%s: NULL endpoint!\n", __func__);
		goto out;
	}
	if (!(dep->flags & DWC3_EP_ENABLED)) {
		pr_debug("%s: disabled endpoint!\n", __func__);
		goto out;
	}
	if (!dep->endpoint.desc) {
		pr_err("%s: NULL endpoint desc!\n", __func__);
		goto out;
	}
	if (!dep->dwc) {
		pr_err("%s: NULL dwc3 ptr!\n", __func__);
		goto out;
	}
	dwc = dep->dwc;

	event.status = 0;

	spin_lock(&dwc->lock);
	dwc3_endpoint_transfer_complete(dep->dwc, dep, &event, 1);
	spin_unlock(&dwc->lock);

out:
	return HRTIMER_NORESTART;
}

static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
		u8 num, u32 direction)
{
@@ -2083,6 +2142,10 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,

		INIT_LIST_HEAD(&dep->request_list);
		INIT_LIST_HEAD(&dep->req_queued);

		hrtimer_init(&dep->xfer_timer, CLOCK_MONOTONIC,
			HRTIMER_MODE_REL);
		dep->xfer_timer.function = dwc3_gadget_ep_timer;
	}

	return 0;
@@ -2191,7 +2254,8 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
			dep->flags &= ~DWC3_EP_MISSED_ISOC;
		}
	} else {
		if (count && (event->status & DEPEVT_STATUS_SHORT))
		if (count && (event->status & DEPEVT_STATUS_SHORT) &&
			!(trb->ctrl & DWC3_TRB_CTRL_CSP))
			s_pkt = 1;
	}

@@ -2227,9 +2291,19 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
	do {
		req = next_request(&dep->req_queued);
		if (!req) {
			if (event->status)
				WARN_ON_ONCE(1);
			return 1;
		}

		/*
		 * For bulk endpoints, HWO bit may be set when the transfer
		 * complete timeout expires.
		 */
		if (usb_endpoint_xfer_bulk(dep->endpoint.desc) &&
			(req->trb->ctrl & DWC3_TRB_CTRL_HWO))
			return 0;

		i = 0;
		do {
			slot = req->start_slot + i;
@@ -2305,6 +2379,16 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
	if (clean_busy)
		dep->flags &= ~DWC3_EP_BUSY;

	if (usb_endpoint_xfer_bulk(dep->endpoint.desc)) {
		/* Cancel transfer complete timer when hitting the last TRB */
		if (!(event->status & DEPEVT_STATUS_LST))
			hrtimer_start(&dep->xfer_timer, ktime_set(0,
				bulk_ep_xfer_timeout_ms * NSEC_PER_MSEC),
				HRTIMER_MODE_REL);
		else
			hrtimer_cancel(&dep->xfer_timer);
	}

	/*
	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
	 * See dwc3_gadget_linksts_change_interrupt() for 1st half.