Commit 636bab75 authored by Selvarasu Ganesan's avatar Selvarasu Ganesan Committed by Wen Zhiwei
Browse files

usb: dwc3: core: Stop processing of pending events if controller is halted

stable inclusion
from stable-v6.6.57
commit 38aef06ea2fd57569e3336f4a4a99d289fc175eb
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IB2M97

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=38aef06ea2fd57569e3336f4a4a99d289fc175eb



--------------------------------

commit 0d410e8913f5cffebcca79ffdd596009d4a13a28 upstream.

This commit addresses an issue where events were being processed when
the controller was in a halted state. To fix this issue by stop
processing the events as the event count was considered stale or
invalid when the controller was halted.

Fixes: fc8bb91b ("usb: dwc3: implement runtime PM")
Cc: stable@kernel.org
Signed-off-by: default avatarSelvarasu Ganesan <selvarasu.g@samsung.com>
Suggested-by: default avatarThinh Nguyen <Thinh.Nguyen@synopsys.com>
Acked-by: default avatarThinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/20240916231813.206-1-selvarasu.g@samsung.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarWen Zhiwei <wenzhiwei@kylinos.cn>
parent ad3b2d61
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -533,6 +533,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length)
int dwc3_event_buffers_setup(struct dwc3 *dwc)
{
	struct dwc3_event_buffer	*evt;
	u32				reg;

	if (!dwc->ev_buf)
		return 0;
@@ -545,8 +546,10 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc)
			upper_32_bits(evt->dma));
	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
			DWC3_GEVNTSIZ_SIZE(evt->length));
	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);

	/* Clear any stale event */
	reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
	return 0;
}

@@ -573,7 +576,10 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
	dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
			| DWC3_GEVNTSIZ_SIZE(0));
	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);

	/* Clear any stale event */
	reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
	dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
}

static void dwc3_core_num_eps(struct dwc3 *dwc)
@@ -2254,7 +2260,11 @@ static int dwc3_runtime_resume(struct device *dev)

	switch (dwc->current_dr_role) {
	case DWC3_GCTL_PRTCAP_DEVICE:
		dwc3_gadget_process_pending_events(dwc);
		if (dwc->pending_events) {
			pm_runtime_put(dwc->dev);
			dwc->pending_events = false;
			enable_irq(dwc->irq_gadget);
		}
		break;
	case DWC3_GCTL_PRTCAP_HOST:
	default:
@@ -2341,6 +2351,12 @@ static void dwc3_complete(struct device *dev)
static const struct dev_pm_ops dwc3_dev_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
	.complete = dwc3_complete,

	/*
	 * Runtime suspend halts the controller on disconnection. It relies on
	 * platforms with custom connection notification to start the controller
	 * again.
	 */
	SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
			dwc3_runtime_idle)
};
+0 −4
Original line number Diff line number Diff line
@@ -1643,7 +1643,6 @@ static inline void dwc3_otg_host_init(struct dwc3 *dwc)
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
int dwc3_gadget_suspend(struct dwc3 *dwc);
int dwc3_gadget_resume(struct dwc3 *dwc);
void dwc3_gadget_process_pending_events(struct dwc3 *dwc);
#else
static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
{
@@ -1655,9 +1654,6 @@ static inline int dwc3_gadget_resume(struct dwc3 *dwc)
	return 0;
}

static inline void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
{
}
#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */

#if IS_ENABLED(CONFIG_USB_DWC3_ULPI)
+0 −11
Original line number Diff line number Diff line
@@ -4741,14 +4741,3 @@ int dwc3_gadget_resume(struct dwc3 *dwc)

	return dwc3_gadget_soft_connect(dwc);
}

void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
{
	if (dwc->pending_events) {
		dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf);
		dwc3_thread_interrupt(dwc->irq_gadget, dwc->ev_buf);
		pm_runtime_put(dwc->dev);
		dwc->pending_events = false;
		enable_irq(dwc->irq_gadget);
	}
}