#define DWC3_CONTROLLER_POST_RESET_EVENT 2
#define DWC3_CORE_PM_SUSPEND_EVENT 3
#define DWC3_CORE_PM_RESUME_EVENT 4
+
+#define MAX_INTR_STATS 10
/**
* struct dwc3 - representation of our controller
* @ctrl_req: usb control request which is used for ep0
* @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode.
* @in_lpm: indicates if controller is in low power mode (no clocks)
* @tx_fifo_size: Available RAM size for TX fifo allocation
+ * @irq_cnt: total irq count
+ * @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;
atomic_t in_lpm;
int tx_fifo_size;
+
+ /* IRQ timing statistics */
+ unsigned long irq_cnt;
+ unsigned bh_completion_time[MAX_INTR_STATS];
+ unsigned bh_handled_evt_cnt[MAX_INTR_STATS];
+ unsigned bh_dbg_index;
+ ktime_t irq_start_time[MAX_INTR_STATS];
+ unsigned irq_completion_time[MAX_INTR_STATS];
+ unsigned irq_event_count[MAX_INTR_STATS];
+ unsigned irq_dbg_index;
};
/* -------------------------------------------------------------------------- */
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, "@ time (us):\t");
+ for (i = 0; i < MAX_INTR_STATS; i++)
+ seq_printf(s, "%lld\t", ktime_to_us(dwc->irq_start_time[i]));
+ seq_puts(s, "\nhard irq time (us):\t");
+ for (i = 0; i < MAX_INTR_STATS; i++)
+ seq_printf(s, "%d\t", dwc->irq_completion_time[i]);
+ seq_puts(s, "\nevents count:\t\t");
+ for (i = 0; i < MAX_INTR_STATS; i++)
+ seq_printf(s, "%d\t", dwc->irq_event_count[i]);
+ seq_puts(s, "\nbh handled count:\t");
+ for (i = 0; i < MAX_INTR_STATS; i++)
+ seq_printf(s, "%d\t", dwc->bh_handled_evt_cnt[i]);
+ seq_puts(s, "\nirq thread time (us):\t");
+ for (i = 0; i < MAX_INTR_STATS; i++)
+ seq_printf(s, "%d\t", dwc->bh_completion_time[i]);
+ seq_putc(s, '\n');
+
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
}
+ dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] += (evt->count / 4);
+
evt->count = 0;
evt->flags &= ~DWC3_EVENT_PENDING;
ret = IRQ_HANDLED;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
int i;
+ unsigned temp_time;
+ ktime_t start_time;
+
+ start_time = ktime_get();
spin_lock_irqsave(&dwc->lock, flags);
+ dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] = 0;
for (i = 0; i < dwc->num_event_buffers; i++)
ret |= dwc3_process_event_buf(dwc, i);
spin_unlock_irqrestore(&dwc->lock, flags);
+ temp_time = ktime_to_us(ktime_sub(ktime_get(), start_time));
+ 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;
}
struct dwc3 *dwc = _dwc;
int i;
irqreturn_t ret = IRQ_NONE;
+ unsigned temp_cnt = 0;
+ ktime_t start_time;
+
+ start_time = ktime_get();
+ dwc->irq_cnt++;
/* controller reset is still pending */
if (dwc->err_evt_seen)
status = dwc3_check_event_buf(dwc, i);
if (status == IRQ_WAKE_THREAD)
ret = status;
+
+ temp_cnt += dwc->ev_buffs[i]->count;
}
+ dwc->irq_start_time[dwc->irq_dbg_index] = start_time;
+ dwc->irq_completion_time[dwc->irq_dbg_index] =
+ ktime_us_delta(ktime_get(), start_time);
+ 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)
pm_runtime_get(dwc->dev);