From 8ef037cd204d8c749cff3fad9b3af7e16254f06c Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 28 May 2019 19:00:07 -0700 Subject: [PATCH] usb: dwc3: Disable the irq before clearing run_stop bit Consider a case of quick pull-up disable after pull-up is enabled. If a SETUP packet comes after bus reset event followed by connection done event, there is a possibility of race between composite_dev_cleanup() freeing cdev->req called from configfs_composite_unbind() and composite_setup() storing req pointer to stack. This causes use after free of cdev->req. Fix this issue by disabling the irq before clearing the run-stop bit so that interrupt handling for setup packet is prevented. In order to prevent running bottom half check pullups_connected flag in dwc3_interrupt and ack the generated events and return. Also flush the bottom half work if there was any work pending before disabling dwc3 irq. Change-Id: I979da8536bd6766153e25cf6120f00f348427a72 Signed-off-by: Chandana Kishori Chiluveru Signed-off-by: Hemant Kumar Signed-off-by: Jack Pham --- drivers/usb/dwc3/gadget.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6627a79920c3..b0672c299a00 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2082,7 +2082,18 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) dev_err(dwc->dev, "timed out waiting for SETUP phase\n"); } + /* pull-up disable: clear pending events without queueing bh */ + dwc->pullups_connected = is_on; + + disable_irq(dwc->irq); + + /* prevent pending bh to run later */ + flush_work(&dwc->bh_work); + spin_lock_irqsave(&dwc->lock, flags); + if (dwc->ep0state != EP0_SETUP_PHASE) + dbg_event(0xFF, "EP0 is not in SETUP phase\n", 0); + /* * If we are here after bus suspend notify otg state machine to * increment pm usage count of dwc to prevent pm_runtime_suspend @@ -2093,6 +2104,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) ret = dwc3_gadget_run_stop(dwc, is_on, false); spin_unlock_irqrestore(&dwc->lock, flags); + enable_irq(dwc->irq); pm_runtime_mark_last_busy(dwc->dev); pm_runtime_put_autosuspend(dwc->dev); @@ -3636,6 +3648,15 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) if (dwc->err_evt_seen) return IRQ_HANDLED; + /* Controller is being halted, ignore the interrupts */ + if (!dwc->pullups_connected) { + count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); + count &= DWC3_GEVNTCOUNT_MASK; + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); + dbg_event(0xFF, "NO_PULLUP", count); + return IRQ_HANDLED; + } + /* * With PCIe legacy interrupt, test shows that top-half irq handler can * be called again after HW interrupt deassertion. Check if bottom-half