usb: dwc3: Implement interrupt moderation

Implement interrupt moderation which allows the interrupt rate to be
throttled. To enable this feature the dwc->imod_interval must be set to
1 or greater. This value specifies the minimum inter-interrupt interval,
in 250 ns increments. A value of 0 disables interrupt moderation.

This applies for DWC_usb3 version 3.00a and higher and for DWC_usb31
version 1.20a and higher.

Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Change-Id: I5c5997c6eea817e49102b8e080f3a9bcf45305b4
Git-commit: cf40b86b6ef6df5262ef5a8463b42524e6aa5590
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
[hemantk@codeaurora.org: removed write to DWC3_DEV_IMOD in dwc3_interrupt,
and fixed merge conflicts]
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
This commit is contained in:
John Youn 2016-11-14 12:32:43 -08:00 committed by Mayank Rana
parent 4be0173416
commit df622b1759
3 changed files with 40 additions and 0 deletions

View file

@ -1000,6 +1000,15 @@ err0:
#define DWC3_ALIGN_MASK (16 - 1)
/* check whether the core supports IMOD */
bool dwc3_has_imod(struct dwc3 *dwc)
{
return ((dwc3_is_usb3(dwc) &&
dwc->revision >= DWC3_REVISION_300A) ||
(dwc3_is_usb31(dwc) &&
dwc->revision >= DWC3_USB31_REVISION_120A));
}
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;

View file

@ -66,6 +66,7 @@
#define DWC3_DEVICE_EVENT_OVERFLOW 11
#define DWC3_GEVNTCOUNT_MASK 0xfffc
#define DWC3_GEVNTCOUNT_EHB (1 << 31)
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
@ -149,6 +150,8 @@
#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10))
#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10))
#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4))
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
@ -433,6 +436,11 @@
#define DWC3_DEPCMD_TYPE_BULK 2
#define DWC3_DEPCMD_TYPE_INTR 3
#define DWC3_DEV_IMOD_COUNT_SHIFT 16
#define DWC3_DEV_IMOD_COUNT_MASK (0xffff << 16)
#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0
#define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0)
/* Structures */
struct dwc3_trb;
@ -837,6 +845,8 @@ struct dwc3_scratchpad_array {
* @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt
* @wait_linkstate: waitqueue for waiting LINK to move into required state
* @vbus_draw: current to be drawn from USB
* @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable.
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@ -920,6 +930,7 @@ struct dwc3 {
#define DWC3_REVISION_260A 0x5533260a
#define DWC3_REVISION_270A 0x5533270a
#define DWC3_REVISION_280A 0x5533280a
#define DWC3_REVISION_300A 0x5533300a
#define DWC3_REVISION_310A 0x5533310a
/*
@ -928,6 +939,7 @@ struct dwc3 {
*/
#define DWC3_REVISION_IS_DWC31 0x80000000
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31)
#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31)
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@ -1008,6 +1020,8 @@ struct dwc3 {
bool b_suspend;
unsigned vbus_draw;
u16 imod_interval;
/* IRQ timing statistics */
int irq;
unsigned long irq_cnt;
@ -1187,6 +1201,8 @@ static inline bool dwc3_is_usb31(struct dwc3 *dwc)
return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
}
bool dwc3_has_imod(struct dwc3 *dwc);
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);

View file

@ -2011,6 +2011,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
int ret = 0;
u32 reg;
/*
* Use IMOD if enabled via dwc->imod_interval. Otherwise, if
* the core supports IMOD, disable it.
*/
if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
} else if (dwc3_has_imod(dwc)) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
@ -3375,6 +3386,10 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
reg &= ~DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
if (dwc->imod_interval)
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf),
DWC3_GEVNTCOUNT_EHB);
return ret;
}