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

Commit a7d5a85a authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 4c196dd0 ec232113
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",