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

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

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

parents ae65a7e6 cc5b27ee
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -543,6 +543,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;
@@ -585,6 +586,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;
	int			fifo_depth;
};

enum dwc3_phy {
@@ -816,7 +818,6 @@ struct dwc3_scratchpad_array {
 * @is_selfpowered: true when we are selfpowered
 * @needs_fifo_resize: not all users might want fifo resizing, flag it
 * @pullups_connected: true when Run/Stop bit is set
 * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
 * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
 * @start_config_issued: true when StartConfig command has been issued
 * @three_stage_setup: set if we perform a three phase setup
@@ -834,6 +835,7 @@ struct dwc3_scratchpad_array {
 * @wait_linkstate: waitqueue for waiting LINK to move into required state
 * @vbus_draw: current to be drawn from USB
 * @dwc_ipc_log_ctxt: dwc3 ipa log context
 * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints
 */
struct dwc3 {
	struct usb_ctrlrequest	*ctrl_req;
@@ -946,7 +948,6 @@ struct dwc3 {
	unsigned		is_selfpowered:1;
	unsigned		needs_fifo_resize:1;
	unsigned		pullups_connected:1;
	unsigned		resize_fifos:1;
	unsigned		setup_packet_pending:1;
	unsigned		three_stage_setup:1;
	unsigned		is_drd:1;
@@ -988,6 +989,7 @@ struct dwc3 {

	wait_queue_head_t	wait_linkstate;
	void			*dwc_ipc_log_ctxt;
	int			last_fifo_depth;
};

/* -------------------------------------------------------------------------- */
@@ -1137,7 +1139,7 @@ struct dwc3_gadget_ep_cmd_params {

/* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep);

#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_host_init(struct dwc3 *dwc);
+6 −1
Original line number Diff line number Diff line
@@ -1167,6 +1167,7 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request)
	const struct usb_endpoint_descriptor *desc = ep->desc;
	const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc;
	u32 reg;
	int ret;

	memset(&params, 0x00, sizeof(params));

@@ -1215,6 +1216,10 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request)

	/* Set XferRsc Index for GSI EP */
	if (!(dep->flags & DWC3_EP_ENABLED)) {
		ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
		if (ret)
			return;

		memset(&params, 0x00, sizeof(params));
		params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
		dwc3_send_gadget_ep_cmd(dwc, dep->number,
+20 −9
Original line number Diff line number Diff line
@@ -586,8 +586,9 @@ 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;

	cfg = le16_to_cpu(ctrl->wValue);

@@ -597,6 +598,24 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
		break;

	case USB_STATE_ADDRESS:
		/* Read ep0IN related TXFIFO size */
		dwc->last_fifo_depth = (dwc3_readl(dwc->regs,
					DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
		/* Clear existing allocated TXFIFO for all IN eps except ep0 */
		for (num = 0; num < dwc->num_in_eps; num++) {
			dep = dwc->eps[(num << 1) | 1];
			if (num) {
				dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), 0);
				dep->fifo_depth = 0;
			} else {
				dep->fifo_depth = dwc->last_fifo_depth;
			}

			dev_dbg(dwc->dev, "%s(): %s dep->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))) {
@@ -621,9 +640,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
							DWC3_DCTL_ACCEPTU2ENA);
				dwc3_writel(dwc->regs, DWC3_DCTL, reg);
			}

			dwc->resize_fifos = true;
			dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
		}
		break;

@@ -1046,11 +1062,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
{
	int ret;
	if (dwc->resize_fifos) {
		dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
		dwc3_gadget_resize_tx_fifos(dwc);
		dwc->resize_fifos = 0;
	}

	ret = dwc3_ep0_start_control_status(dep);
	if (WARN_ON_ONCE(ret))
+61 −83
Original line number Diff line number Diff line
@@ -183,91 +183,64 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
 *
 * Unfortunately, due to many variables that's not always the case.
 */
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
{
	int		last_fifo_depth = 0;
	int		ram1_depth;
	int		fifo_size;
	int		mdwidth;
	int		num;
	int		num_eps;
	int		max_packet = 1024;
	struct usb_composite_dev *cdev = get_gadget_data(&dwc->gadget);

	if (!(cdev && cdev->config) || !dwc->needs_fifo_resize)
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep)
{
	int		fifo_size, mdwidth, max_packet = 1024;
	int		tmp, mult = 1;

	if (!dwc->needs_fifo_resize)
		return 0;

	num_eps = dwc->num_in_eps;
	ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
	mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
	/* resize IN endpoints excepts ep0 */
	if (!usb_endpoint_dir_in(dep->endpoint.desc) ||
			dep->endpoint.ep_num == 0)
		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;
	last_fifo_depth = (dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
	dev_dbg(dwc->dev, "%s: num eps:%d max_packet:%d last_fifo_depth:%04x\n",
				__func__, num_eps, max_packet, last_fifo_depth);

	/* Don't resize ep0IN TxFIFO, start with ep1IN only. */
	for (num = 1; num < num_eps; num++) {
		/* bit0 indicates direction; 1 means IN ep */
		struct dwc3_ep	*dep = dwc->eps[(num << 1) | 1];
		int		mult = 1;
		int		tmp;

		tmp = max_packet + mdwidth;
		/*
		 * Interfaces like MBIM or ECM is having multiple data
		 * interfaces. SET_CONFIG() happens before set_alt with
		 * data interface 1 which results into calling this API
		 * before GSI endpoint enabled. This results no txfifo
		 * resize with GSI endpoint causing low throughput. Hence
		 * use mult as 3 for GSI IN endpoint always irrespective
		 * USB speed.
		 */
		if (dep->endpoint.ep_type == EP_TYPE_GSI ||
				dep->endpoint.endless)
			mult = 3;

		if (num == high_bw_ep_in_num)
	if (dep->endpoint.ep_type == EP_TYPE_GSI || dep->endpoint.endless)
		mult = 3;

		if (!(dep->flags & DWC3_EP_ENABLED)) {
			dev_dbg(dwc->dev, "ep%dIn not enabled", num);
			goto resize_fifo;
		}

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

resize_fifo:
		tmp *= mult;
		tmp += mdwidth;

	tmp = ((max_packet + mdwidth) * mult) + mdwidth;
	fifo_size = DIV_ROUND_UP(tmp, mdwidth);
	dep->fifo_depth = fifo_size;
	fifo_size |= (dwc->last_fifo_depth << 16);
	dwc->last_fifo_depth += (fifo_size & 0xffff);

		fifo_size |= (last_fifo_depth << 16);
	dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n",
		dep->endpoint.name, dep->endpoint.ep_num, dwc->last_fifo_depth,
		dep->fifo_depth);

		dev_dbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
				dep->name, last_fifo_depth, fifo_size & 0xffff);

		last_fifo_depth += (fifo_size & 0xffff);
	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->tx_fifo_size &&
				(last_fifo_depth >= dwc->tx_fifo_size)) {
			/*
			 * Fifo size allocated exceeded available RAM size.
			 * Hence return error.
			 */
			dev_err(dwc->dev, "Fifosize(%d) > available RAM(%d)\n",
					last_fifo_depth, dwc->tx_fifo_size);
		((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);
		dwc->last_fifo_depth -= (fifo_size & 0xffff);
		dep->fifo_depth = 0;
		WARN_ON(1);
		return -ENOMEM;
	}

		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);

	}

	dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->endpoint.ep_num),
							fifo_size);
	return 0;
}

@@ -626,6 +599,17 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);

	if (!(dep->flags & DWC3_EP_ENABLED)) {
		dep->endpoint.desc = desc;
		dep->comp_desc = comp_desc;
		dep->type = usb_endpoint_type(desc);
		ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
		if (ret) {
			dep->endpoint.desc = NULL;
			dep->comp_desc = NULL;
			dep->type = 0;
			return ret;
		}

		ret = dwc3_gadget_start_config(dwc, dep);
		if (ret) {
			dev_err(dwc->dev, "start_config() failed for %s\n",
@@ -645,9 +629,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
		struct dwc3_trb	*trb_st_hw;
		struct dwc3_trb	*trb_link;

		dep->endpoint.desc = desc;
		dep->comp_desc = comp_desc;
		dep->type = usb_endpoint_type(desc);
		dep->flags |= DWC3_EP_ENABLED;

		reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
@@ -3020,9 +3001,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
	dwc3_stop_active_transfers(dwc);
	dwc3_clear_stall_all_ep(dwc);

	/* bus reset issued due to missing status stage of a control transfer */
	dwc->resize_fifos = 0;

	/* Reset device address to zero */
	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
	reg &= ~(DWC3_DCFG_DEVADDR_MASK);