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

Commit ec232113 authored by Mayank Rana's avatar Mayank Rana Committed by Jack Pham
Browse files

usb: dwc3: resize txfifo of IN/INT endpoint before enabling it



USB IN/INT endpoint stalls when performing TX FIFO resize functionality
when IN/INT endpoint is already active i.e. usb endpoint is enabled and
usb request is pending with it. Fix this issue by making sure that TX
FIFO resize is performed before enabling endpoint which shall happen
after set_alt(1) and before any function queues request with its
allocated USB endpoint.

This commit also squashes the following commits from previous kernels:

  Revert "usb: dwc3: drop FIFO resizing logic"
  dwc3: gadget: Improve TX FIFO resize functionality
  dwc3: gadget: Use default TX FIFO size as 1024 bytes with each IN eps
  usb: gadget: Use mult as 3 for GSI related USB IN endpoint always
  USB: dwc3: gadget: Fix TxFIFO resizing logic
  dwc3: Preserve TxFIFO of IN/INT EP for UDC without tx-fifo-resize
  dwc3: gadget: Use TXFIFO register based on used dwc3 version
  dwc3: gadget: Increase TXFIFO size as 6KB for GSI IN endpoint
  usb: dwc3: Change TXFIFO size for GSI IN EP based on controller
  usb: dwc3: gadget: Fix TXFIFO resize logic for non-zero EPs
  usb: dwc3: Increase the TxFIFO resize factor

Change-Id: I13a590f87ab8492f7c95a15b2da9f00c9c63c4f9
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent f84c92f1
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1347,6 +1347,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
	device_property_read_u8(dev, "snps,tx-max-burst-prd",
				&tx_max_burst_prd);

	dwc->needs_fifo_resize = device_property_read_bool(dev,
				"tx-fifo-resize");

	dwc->disable_scramble_quirk = device_property_read_bool(dev,
				"snps,disable_scramble_quirk");
	dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
+11 −0
Original line number Diff line number Diff line
@@ -726,6 +726,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
 * @fifo_depth: allocated TXFIFO depth
 */
struct dwc3_ep {
	struct usb_ep		endpoint;
@@ -1062,6 +1063,7 @@ struct dwc3_scratchpad_array {
 * 	1	- utmi_l1_suspend_n
 * @is_fpga: true when we are using the FPGA board
 * @pending_events: true when we have pending IRQs to be handled
 * @needs_fifo_resize: not all users might want fifo resizing, flag it
 * @pullups_connected: true when Run/Stop bit is set
 * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
 * @three_stage_setup: set if we perform a three phase setup
@@ -1111,6 +1113,8 @@ struct dwc3_scratchpad_array {
 * @xhci_imod_value: imod value to use with xhci
 * @index: dwc3's instance number
 * @dwc_ipc_log_ctxt: dwc3 ipc log context
 * @tx_fifo_size: Available RAM size for TX fifo allocation
 * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints
 * @irq_cnt: total irq count
 * @bh_completion_time: time taken for taklet completion
 * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt
@@ -1275,6 +1279,7 @@ struct dwc3 {
	unsigned		is_utmi_l1_suspend:1;
	unsigned		is_fpga:1;
	unsigned		pending_events:1;
	unsigned		needs_fifo_resize:1;
	unsigned		pullups_connected:1;
	unsigned		setup_packet_pending:1;
	unsigned		three_stage_setup:1;
@@ -1322,6 +1327,8 @@ struct dwc3 {
	unsigned int		index;
	void			*dwc_ipc_log_ctxt;
	struct dwc3_gadget_events	dbg_gadget_events;
	int			tx_fifo_size;
	int			last_fifo_depth;

	/* IRQ timing statistics */
	int			irq;
@@ -1538,6 +1545,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
		struct dwc3_gadget_ep_cmd_params *params);
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep);
void dwc3_gadget_disable_irq(struct dwc3 *dwc);
int dwc3_core_init(struct dwc3 *dwc);
int dwc3_event_buffers_setup(struct dwc3 *dwc);
@@ -1562,6 +1570,9 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
		int cmd, u32 param)
{ return 0; }
static inline int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc,
		struct dwc3_ep *dep)
{ return 0; }
static inline void dwc3_gadget_disable_irq(struct dwc3 *dwc)
{ }
static int dwc3_core_init(struct dwc3 *dwc)
+39 −1
Original line number Diff line number Diff line
@@ -603,8 +603,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
	enum usb_device_state state = dwc->gadget.state;
	u32 cfg;
	int ret;
	int ret, num;
	u32 reg;
	struct dwc3_ep	*dep;
	int size;

	cfg = le16_to_cpu(ctrl->wValue);

@@ -613,6 +615,42 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
		return -EINVAL;

	case USB_STATE_ADDRESS:
		/*
		 * If tx-fifo-resize flag is not set for the controller, then
		 * do not clear existing allocated TXFIFO since we do not
		 * allocate it again in dwc3_gadget_resize_tx_fifos
		 */
		if (dwc->needs_fifo_resize && dwc->tx_fifo_size) {
			/* Read ep0IN related TXFIFO size */
			dep = dwc->eps[1];
			size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
			if (dwc3_is_usb31(dwc))
				dep->fifo_depth = DWC31_GTXFIFOSIZ_TXFDEF(size);
			else
				dep->fifo_depth = DWC3_GTXFIFOSIZ_TXFDEF(size);

			dwc->last_fifo_depth = dep->fifo_depth;
			/* Clear existing TXFIFO for all IN eps except ep0 */
			for (num = 3; num < min_t(int, dwc->num_eps,
						DWC3_ENDPOINTS_NUM); num += 2) {
				dep = dwc->eps[num];
				size = 0;
				/* Don't change TXFRAMNUM on usb31 version */
				if (dwc3_is_usb31(dwc))
					size = dwc3_readl(dwc->regs,
						DWC3_GTXFIFOSIZ(num >> 1)) &
						DWC31_GTXFIFOSIZ_TXFRAMNUM;

				dwc3_writel(dwc->regs,
					DWC3_GTXFIFOSIZ(num >> 1), size);
				dep->fifo_depth = 0;

				dev_dbg(dwc->dev, "%s(): %s fifo_depth:%x\n",
					__func__, dep->name, dep->fifo_depth);
				dbg_event(0xFF, "fifo_reset", dep->number);
			}
		}

		ret = dwc3_ep0_delegate_req(dwc, ctrl);
		/* if the cfg matches and the cfg is non zero */
		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
+98 −0
Original line number Diff line number Diff line
@@ -172,6 +172,100 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
	dwc3_ep_inc_trb(&dep->trb_dequeue);
}

/*
 * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
 * @dwc: pointer to our context structure
 *
 * This function will a best effort FIFO allocation in order
 * to improve FIFO usage and throughput, while still allowing
 * us to enable as many endpoints as possible.
 *
 * Keep in mind that this operation will be highly dependent
 * on the configured size for RAM1 - which contains TxFifo -,
 * the amount of endpoints enabled on coreConsultant tool, and
 * the width of the Master Bus.
 *
 * In the ideal world, we would always be able to satisfy the
 * following equation:
 *
 * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
 * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
 *
 * Unfortunately, due to many variables that's not always the case.
 */
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep)
{
	int		fifo_size, mdwidth, max_packet = 1024;
	int		tmp, mult = 1, fifo_0_start;

	if (!dwc->needs_fifo_resize || !dwc->tx_fifo_size)
		return 0;

	/* resize IN endpoints excepts ep0 */
	if (!usb_endpoint_dir_in(dep->endpoint.desc) || dep->number <= 1)
		return 0;

	/* Don't resize already resized IN endpoint */
	if (dep->fifo_depth) {
		dev_dbg(dwc->dev, "%s fifo_depth:%d is already set\n",
				dep->endpoint.name, dep->fifo_depth);
		return 0;
	}

	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
	/* MDWIDTH is represented in bits, we need it in bytes */
	mdwidth >>= 3;

	if (((dep->endpoint.maxburst > 1) &&
			usb_endpoint_xfer_bulk(dep->endpoint.desc))
			|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
		mult = 3;

	if ((dep->endpoint.maxburst > 6) &&
			usb_endpoint_xfer_bulk(dep->endpoint.desc)
			&& dwc3_is_usb31(dwc))
		mult = 6;

	tmp = ((max_packet + mdwidth) * mult) + mdwidth;
	fifo_size = DIV_ROUND_UP(tmp, mdwidth);
	dep->fifo_depth = fifo_size;

	/* Check if TXFIFOs start at non-zero addr */
	tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
	fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp);

	fifo_size |= (fifo_0_start + (dwc->last_fifo_depth << 16));
	if (dwc3_is_usb31(dwc))
		dwc->last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEF(fifo_size);
	else
		dwc->last_fifo_depth += DWC3_GTXFIFOSIZ_TXFDEF(fifo_size);

	dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n",
		dep->endpoint.name, dep->number >> 1, dwc->last_fifo_depth,
		dep->fifo_depth);

	dbg_event(0xFF, "resize_fifo", dep->number);
	dbg_event(0xFF, "fifo_depth", dep->fifo_depth);
	/* Check fifo size allocation doesn't exceed available RAM size. */
	if ((dwc->last_fifo_depth * mdwidth) >= dwc->tx_fifo_size) {
		dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n",
			(dwc->last_fifo_depth * mdwidth), dwc->tx_fifo_size,
			dep->endpoint.name, fifo_size);
		if (dwc3_is_usb31(dwc))
			fifo_size = DWC31_GTXFIFOSIZ_TXFDEF(fifo_size);
		else
			fifo_size = DWC3_GTXFIFOSIZ_TXFDEF(fifo_size);
		dwc->last_fifo_depth -= fifo_size;
		dep->fifo_depth = 0;
		WARN_ON(1);
		return -ENOMEM;
	}

	dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size);
	return 0;
}
EXPORT_SYMBOL(dwc3_gadget_resize_tx_fifos);

static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
		struct dwc3_request *req, int status)
{
@@ -630,6 +724,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
	int			ret;

	if (!(dep->flags & DWC3_EP_ENABLED)) {
		ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
		if (ret)
			return ret;

		ret = dwc3_gadget_start_config(dep);
		if (ret) {
			dev_err(dwc->dev, "start_config() failed for %s\n",