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

Commit 51519df0 authored by Mayank Rana's avatar Mayank Rana
Browse files

dwc3: Check USB LPM status before accessing any register



USB debugfs entries can be accessed when USB session is not active or
USB is in low power mode. This results into unclocked register access.
Fix this issue by checking USB LPM status.

debugfs_create_regset32() fops related APIs are used to get USB dwc3
register dump. These fops don't have support to query device status
before accessing registers. Hence by default disabling creation of
regdump debugfs entry.

Change-Id: I67b00532eca159e000c848cb056d9759c47aefe9
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent b1efd310
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -951,6 +951,7 @@ struct dwc3_scratchpad_array {
 * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints
 * @imod_interval: set the interrupt moderation interval in 250ns
 *			increments or 0 to disable.
 * @create_reg_debugfs: create debugfs entry to allow dwc3 register dump
 */
struct dwc3 {
	struct usb_ctrlrequest	*ctrl_req;
@@ -1145,6 +1146,7 @@ struct dwc3 {
	void			*dwc_ipc_log_ctxt;
	int			last_fifo_depth;
	struct dwc3_gadget_events	dbg_gadget_events;
	bool			create_reg_debugfs;
};

/* -------------------------------------------------------------------------- */
+72 −3
Original line number Diff line number Diff line
@@ -291,6 +291,11 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			reg;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
	spin_unlock_irqrestore(&dwc->lock, flags);
@@ -326,6 +331,11 @@ static ssize_t dwc3_mode_write(struct file *file,
	u32			mode = 0;
	char buf[32] = {};

	if (atomic_read(&dwc->in_lpm)) {
		dev_err(dwc->dev, "USB device is powered off\n");
		return count;
	}

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

@@ -360,6 +370,12 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			reg;


	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	reg &= DWC3_DCTL_TSTCTRL_MASK;
@@ -406,6 +422,11 @@ static ssize_t dwc3_testmode_write(struct file *file,
	u32			testmode = 0;
	char			buf[32] = {};

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

@@ -444,6 +465,11 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
	enum dwc3_link_state	state;
	u32			reg;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
	state = DWC3_DSTS_USBLNKST(reg);
@@ -513,6 +539,11 @@ static ssize_t dwc3_link_state_write(struct file *file,
	enum dwc3_link_state	state = 0;
	char			buf[32] = {};

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

@@ -558,6 +589,11 @@ static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			val;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ);
	seq_printf(s, "%u\n", val);
@@ -573,6 +609,11 @@ static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			val;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ);
	seq_printf(s, "%u\n", val);
@@ -588,6 +629,11 @@ static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			val;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	val = dwc3_core_fifo_space(dep, DWC3_TXREQQ);
	seq_printf(s, "%u\n", val);
@@ -603,6 +649,11 @@ static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			val;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	val = dwc3_core_fifo_space(dep, DWC3_RXREQQ);
	seq_printf(s, "%u\n", val);
@@ -618,6 +669,11 @@ static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			val;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ);
	seq_printf(s, "%u\n", val);
@@ -633,6 +689,11 @@ static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			val;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ);
	seq_printf(s, "%u\n", val);
@@ -648,6 +709,11 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused)
	unsigned long		flags;
	u32			val;

	if (atomic_read(&dwc->in_lpm)) {
		seq_puts(s, "USB device is powered off\n");
		return 0;
	}

	spin_lock_irqsave(&dwc->lock, flags);
	val = dwc3_core_fifo_space(dep, DWC3_EVENTQ);
	seq_printf(s, "%u\n", val);
@@ -1044,9 +1110,12 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
	dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
	dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;

	file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
	if (dwc->create_reg_debugfs) {
		file = debugfs_create_regset32("regdump", 0444,
						root, dwc->regset);
		if (!file)
			dev_dbg(dwc->dev, "Can't create debugfs regdump\n");
	}

	if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
		file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,