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

Commit 95411c3b authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: dwc3: Offload IRQ handling to softirq context"

parents 9c4067b3 99a88364
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -717,6 +717,8 @@ struct dwc3_scratchpad_array {
#define DWC3_CORE_PM_RESUME_EVENT			6
#define DWC3_CONTROLLER_POST_INITIALIZATION_EVENT	7
#define DWC3_CONTROLLER_CONNDONE_EVENT			8

#define MAX_INTR_STATS				10
/**
 * struct dwc3 - representation of our controller
 * @ctrl_req: usb control request which is used for ep0
@@ -773,6 +775,11 @@ struct dwc3_scratchpad_array {
 * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode.
 * @hird_thresh: value to configure in DCTL[HIRD_Thresh]
 * @in_lpm: if 1, indicates that the controller is in low power mode (no clocks)
 * @irq: irq number
 * @bh: tasklet which handles the interrupt
 * @bh_completion_time: time taken for taklet completion
 * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt
 * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt
 */
struct dwc3 {
	struct usb_ctrlrequest	*ctrl_req;
@@ -886,6 +893,13 @@ struct dwc3 {
	u8			hird_thresh;
	atomic_t		in_lpm;
	struct dwc3_gadget_events	dbg_gadget_events;

	/* offload IRQ handling to tasklet */
	int			irq;
	struct tasklet_struct	bh;
	unsigned                bh_completion_time[MAX_INTR_STATS];
	unsigned                bh_handled_evt_cnt[MAX_INTR_STATS];
	unsigned                bh_dbg_index;
};

/* -------------------------------------------------------------------------- */
+9 −0
Original line number Diff line number Diff line
@@ -1174,6 +1174,15 @@ static int dwc3_gadget_int_events_show(struct seq_file *s, void *unused)
		dbg_gadget_events->cmdcmplt);
	seq_printf(s, "unknown_event:%u\n", dbg_gadget_events->unknown_event);

	seq_printf(s, "\n\t== Last %d interrupts stats ==\t\n", MAX_INTR_STATS);
	seq_puts(s, "events count:\t");
	for (i = 0; i < MAX_INTR_STATS; i++)
		seq_printf(s, "%d\t", dwc->bh_handled_evt_cnt[i]);
	seq_puts(s, "\ntasklet time:\t");
	for (i = 0; i < MAX_INTR_STATS; i++)
		seq_printf(s, "%d\t", dwc->bh_completion_time[i]);
	seq_puts(s, "\n(usec)\n");

	spin_unlock_irqrestore(&dwc->lock, flags);
	return 0;
}
+34 −7
Original line number Diff line number Diff line
@@ -2131,8 +2131,8 @@ static int dwc3_gadget_start(struct usb_gadget *g,

	pm_runtime_get_sync(dwc->dev);
	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
	ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
			IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
	dwc->irq = irq;
	ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED, "dwc3", dwc);
	if (ret) {
		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
				irq, ret);
@@ -2185,9 +2185,12 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
	unsigned long		flags;
	int			irq;

	dwc3_gadget_disable_irq(dwc);

	tasklet_kill(&dwc->bh);

	spin_lock_irqsave(&dwc->lock, flags);

	dwc3_gadget_disable_irq(dwc);
	__dwc3_gadget_ep_disable(dwc->eps[0]);
	__dwc3_gadget_ep_disable(dwc->eps[1]);

@@ -3316,6 +3319,10 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
	unsigned long flags;
	irqreturn_t ret = IRQ_NONE;
	int i;
	unsigned temp_cnt = 0, temp_time;
	ktime_t start_time;

	start_time = ktime_get();

	spin_lock_irqsave(&dwc->lock, flags);

@@ -3325,6 +3332,7 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)

		evt = dwc->ev_buffs[i];
		left = evt->count;
		temp_cnt = temp_cnt + evt->count;

		if (!(evt->flags & DWC3_EVENT_PENDING))
			continue;
@@ -3358,6 +3366,12 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)

	spin_unlock_irqrestore(&dwc->lock, flags);

	temp_time = ktime_to_us(ktime_sub(ktime_get(), start_time));
	temp_cnt = temp_cnt / 4;
	dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] = temp_cnt;
	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;
}
@@ -3380,6 +3394,15 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
	return IRQ_WAKE_THREAD;
}

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_interrupt(int irq, void *_dwc)
{
	struct dwc3			*dwc = _dwc;
@@ -3398,10 +3421,11 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)

	spin_unlock(&dwc->lock);

	if (ret == IRQ_WAKE_THREAD)
		pm_runtime_get(dwc->dev);

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

/**
@@ -3457,6 +3481,9 @@ int dwc3_gadget_init(struct dwc3 *dwc)
		goto err3;
	}

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

	dwc->gadget.ops			= &dwc3_gadget_ops;
	if (dwc->maximum_speed == USB_SPEED_SUPER)
		dwc->gadget.max_speed		= USB_SPEED_SUPER;