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

Commit 78c7c287 authored by Hemant Kumar's avatar Hemant Kumar Committed by Mayank Rana
Browse files

usb: dwc3: Remove tasklet bottom half handler



There is a possibility of tasklet bottom half handler racing
with dwc3_msm_suspend(). As a result before disabling the dwc3
irq, dwc3 interrupts are fired and once the suspend routine
disables the clocks bottom half handler gets a chance to run
and tries to access dwc3 register resulting into un-clocked
register access. Since dwc3 interrupt is already running in
threaded irq context, interrupt can be directly handled in
same context and avoid this race.

Change-Id: Ife9e165f6aa2112c1440819d659b97b5502a3f07
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent d72bafee
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -1061,7 +1061,6 @@ struct dwc3 {

	/* IRQ timing statistics */
	int			irq;
	struct tasklet_struct	bh;
	unsigned long		irq_cnt;
	unsigned int		bh_completion_time[MAX_INTR_STATS];
	unsigned int		bh_handled_evt_cnt[MAX_INTR_STATS];
+2 −18
Original line number Diff line number Diff line
@@ -2079,7 +2079,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
	unsigned long	flags;

	pm_runtime_get_sync(dwc->dev);
	tasklet_kill(&dwc->bh);

	spin_lock_irqsave(&dwc->lock, flags);
	__dwc3_gadget_stop(dwc);
@@ -3276,15 +3275,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc)
	return ret;
}

static void dwc3_interrupt_bh(unsigned long param)
{
	struct dwc3 *dwc = (struct dwc3 *) param;

	pm_runtime_get(dwc->dev);
	dwc3_thread_interrupt(dwc->irq, dwc);
	enable_irq(dwc->irq);
}

static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
{
	struct dwc3 *dwc = _dwc;
@@ -3306,7 +3296,6 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
	dwc->bh_completion_time[dwc->bh_dbg_index] = temp_time;
	dwc->bh_dbg_index = (dwc->bh_dbg_index + 1) % 10;

	pm_runtime_put(dwc->dev);
	return ret;
}

@@ -3366,10 +3355,8 @@ irqreturn_t dwc3_interrupt(int irq, void *_dwc)
	dwc->irq_event_count[dwc->irq_dbg_index] = temp_cnt / 4;
	dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS;

	if (ret == IRQ_WAKE_THREAD) {
		disable_irq_nosync(irq);
		tasklet_schedule(&dwc->bh);
	}
	if (ret == IRQ_WAKE_THREAD)
		dwc3_thread_interrupt(dwc->irq, dwc);

	return IRQ_HANDLED;
}
@@ -3449,9 +3436,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
		goto err4;
	}

	dwc->bh.func = dwc3_interrupt_bh;
	dwc->bh.data = (unsigned long)dwc;

	dwc->gadget.ops			= &dwc3_gadget_ops;
	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
	dwc->gadget.sg_supported	= true;