[PATCH v4 2/3] 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 --- drivers/usb/dwc3/core.c | 16 drivers/usb/dwc3/core.h | 15 +++ drivers/usb/dwc3/gadget.c | 16 3 files changed, 47 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 87d0cfb..889dbab 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -982,12 +982,28 @@ static void dwc3_get_properties(struct dwc3 *dwc) dwc->hird_threshold = hird_threshold | (dwc->is_utmi_l1_suspend << 4); + dwc->imod_interval = 0; +} + +/* 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 void dwc3_check_params(struct dwc3 *dwc) { struct device *dev = dwc->dev; + /* Check for proper value of imod_interval */ + if (dwc->imod_interval && !dwc3_has_imod(dwc)) { + dev_warn(dwc->dev, "Interrupt moderation not supported\n"); + dwc->imod_interval = 0; + } + /* Check the maximum_speed parameter */ switch (dwc->maximum_speed) { case USB_SPEED_LOW: diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index bf63756..ef81fa5 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -67,6 +67,7 @@ #define DWC3_DEVICE_EVENT_OVERFLOW 11 #define DWC3_GEVNTCOUNT_MASK 0xfffc +#define DWC3_GEVNTCOUNT_EHB(1 << 31) #define DWC3_GSNPSID_MASK 0x #define DWC3_GSNPSREV_MASK 0x @@ -149,6 +150,8 @@ #define DWC3_DEPCMDPAR00x08 #define DWC3_DEPCMD0x0c +#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4)) + /* OTG Registers */ #define DWC3_OCFG 0xcc00 #define DWC3_OCTL 0xcc04 @@ -465,6 +468,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 (0x << 16) +#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0 +#define DWC3_DEV_IMOD_INTERVAL_MASK(0x << 0) + /* Structures */ struct dwc3_trb; @@ -846,6 +854,8 @@ struct dwc3_scratchpad_array { * 1 - -3.5dB de-emphasis * 2 - No de-emphasis * 3 - Reserved + * @imod_interval: set the interrupt moderation interval in 250ns + * increments or 0 to disable. */ struct dwc3 { struct usb_ctrlrequest *ctrl_req; @@ -933,6 +943,7 @@ struct dwc3 { */ #define DWC3_REVISION_IS_DWC31 0x8000 #define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31) +#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; @@ -991,6 +1002,8 @@ struct dwc3 { unsignedtx_de_emphasis_quirk:1; unsignedtx_de_emphasis:2; + + u16 imod_interval; }; /* -- */ @@ -1162,6 +1175,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); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index baa2c64..0973167 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1685,6 +1685,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); @@ -2847,6 +2858,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) reg &= ~DWC3_GEVNTSIZ_INTMASK; dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); +
Re: [PATCH v4 2/3] usb: dwc3: Implement interrupt moderation
Hi, John Youn writes: > 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 > --- > drivers/usb/dwc3/core.c | 16 > drivers/usb/dwc3/core.h | 15 +++ > drivers/usb/dwc3/gadget.c | 16 > 3 files changed, 47 insertions(+) > > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c > index 87d0cfb..889dbab 100644 > --- a/drivers/usb/dwc3/core.c > +++ b/drivers/usb/dwc3/core.c > @@ -982,12 +982,28 @@ static void dwc3_get_properties(struct dwc3 *dwc) > dwc->hird_threshold = hird_threshold > | (dwc->is_utmi_l1_suspend << 4); > > + dwc->imod_interval = 0; > +} > + > +/* 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 void dwc3_check_params(struct dwc3 *dwc) > { > struct device *dev = dwc->dev; > > + /* Check for proper value of imod_interval */ > + if (dwc->imod_interval && !dwc3_has_imod(dwc)) { > + dev_warn(dwc->dev, "Interrupt moderation not supported\n"); > + dwc->imod_interval = 0; > + } > + > /* Check the maximum_speed parameter */ > switch (dwc->maximum_speed) { > case USB_SPEED_LOW: > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h > index bf63756..ef81fa5 100644 > --- a/drivers/usb/dwc3/core.h > +++ b/drivers/usb/dwc3/core.h > @@ -67,6 +67,7 @@ > #define DWC3_DEVICE_EVENT_OVERFLOW 11 > > #define DWC3_GEVNTCOUNT_MASK 0xfffc > +#define DWC3_GEVNTCOUNT_EHB (1 << 31) > #define DWC3_GSNPSID_MASK0x > #define DWC3_GSNPSREV_MASK 0x > > @@ -149,6 +150,8 @@ > #define DWC3_DEPCMDPAR0 0x08 > #define DWC3_DEPCMD 0x0c > > +#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4)) > + > /* OTG Registers */ > #define DWC3_OCFG0xcc00 > #define DWC3_OCTL0xcc04 > @@ -465,6 +468,11 @@ > #define DWC3_DEPCMD_TYPE_BULK2 > #define DWC3_DEPCMD_TYPE_INTR3 > > +#define DWC3_DEV_IMOD_COUNT_SHIFT16 > +#define DWC3_DEV_IMOD_COUNT_MASK (0x << 16) > +#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0 > +#define DWC3_DEV_IMOD_INTERVAL_MASK (0x << 0) > + > /* Structures */ > > struct dwc3_trb; > @@ -846,6 +854,8 @@ struct dwc3_scratchpad_array { > * 1 - -3.5dB de-emphasis > * 2 - No de-emphasis > * 3 - Reserved > + * @imod_interval: set the interrupt moderation interval in 250ns > + * increments or 0 to disable. > */ > struct dwc3 { > struct usb_ctrlrequest *ctrl_req; > @@ -933,6 +943,7 @@ struct dwc3 { > */ > #define DWC3_REVISION_IS_DWC31 0x8000 > #define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31) > +#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) > > enum dwc3_ep0_next ep0_next_event; > enum dwc3_ep0_state ep0state; > @@ -991,6 +1002,8 @@ struct dwc3 { > > unsignedtx_de_emphasis_quirk:1; > unsignedtx_de_emphasis:2; > + > + u16 imod_interval; > }; > > /* > -- */ > @@ -1162,6 +1175,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); > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c > index baa2c64..0973167 100644 > --- a/drivers/usb/dwc3/gadget.c > +++ b/drivers/usb/dwc3/gadget.c > @@ -1685,6 +1685,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); is this safe? You're doing this after request_threaded_irq(). Sure, IRQs are still masked, but couldn't clear events that would get fired as soon as we unmask events? > + } else if (dwc3_has_imod(d
Re: [PATCH v4 2/3] usb: dwc3: Implement interrupt moderation
On 11/15/2016 3:16 AM, Felipe Balbi wrote: > > Hi, > > John Youn writes: >> 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 >> --- >> drivers/usb/dwc3/core.c | 16 >> drivers/usb/dwc3/core.h | 15 +++ >> drivers/usb/dwc3/gadget.c | 16 >> 3 files changed, 47 insertions(+) >> >> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c >> index 87d0cfb..889dbab 100644 >> --- a/drivers/usb/dwc3/core.c >> +++ b/drivers/usb/dwc3/core.c >> @@ -982,12 +982,28 @@ static void dwc3_get_properties(struct dwc3 *dwc) >> dwc->hird_threshold = hird_threshold >> | (dwc->is_utmi_l1_suspend << 4); >> >> +dwc->imod_interval = 0; >> +} >> + >> +/* 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 void dwc3_check_params(struct dwc3 *dwc) >> { >> struct device *dev = dwc->dev; >> >> +/* Check for proper value of imod_interval */ >> +if (dwc->imod_interval && !dwc3_has_imod(dwc)) { >> +dev_warn(dwc->dev, "Interrupt moderation not supported\n"); >> +dwc->imod_interval = 0; >> +} >> + >> /* Check the maximum_speed parameter */ >> switch (dwc->maximum_speed) { >> case USB_SPEED_LOW: >> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h >> index bf63756..ef81fa5 100644 >> --- a/drivers/usb/dwc3/core.h >> +++ b/drivers/usb/dwc3/core.h >> @@ -67,6 +67,7 @@ >> #define DWC3_DEVICE_EVENT_OVERFLOW 11 >> >> #define DWC3_GEVNTCOUNT_MASK0xfffc >> +#define DWC3_GEVNTCOUNT_EHB (1 << 31) >> #define DWC3_GSNPSID_MASK 0x >> #define DWC3_GSNPSREV_MASK 0x >> >> @@ -149,6 +150,8 @@ >> #define DWC3_DEPCMDPAR0 0x08 >> #define DWC3_DEPCMD 0x0c >> >> +#define DWC3_DEV_IMOD(n)(0xca00 + (n * 0x4)) >> + >> /* OTG Registers */ >> #define DWC3_OCFG 0xcc00 >> #define DWC3_OCTL 0xcc04 >> @@ -465,6 +468,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(0x << 16) >> +#define DWC3_DEV_IMOD_INTERVAL_SHIFT0 >> +#define DWC3_DEV_IMOD_INTERVAL_MASK (0x << 0) >> + >> /* Structures */ >> >> struct dwc3_trb; >> @@ -846,6 +854,8 @@ struct dwc3_scratchpad_array { >> * 1 - -3.5dB de-emphasis >> * 2 - No de-emphasis >> * 3 - Reserved >> + * @imod_interval: set the interrupt moderation interval in 250ns >> + * increments or 0 to disable. >> */ >> struct dwc3 { >> struct usb_ctrlrequest *ctrl_req; >> @@ -933,6 +943,7 @@ struct dwc3 { >> */ >> #define DWC3_REVISION_IS_DWC31 0x8000 >> #define DWC3_USB31_REVISION_110A(0x3131302a | DWC3_REVISION_IS_DWC31) >> +#define DWC3_USB31_REVISION_120A(0x3132302a | DWC3_REVISION_IS_DWC31) >> >> enum dwc3_ep0_next ep0_next_event; >> enum dwc3_ep0_state ep0state; >> @@ -991,6 +1002,8 @@ struct dwc3 { >> >> unsignedtx_de_emphasis_quirk:1; >> unsignedtx_de_emphasis:2; >> + >> +u16 imod_interval; >> }; >> >> /* >> -- */ >> @@ -1162,6 +1175,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); >> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c >> index baa2c64..0973167 100644 >> --- a/drivers/usb/dwc3/gadget.c >> +++ b/drivers/usb/dwc3/gadget.c >> @@ -1685,6 +1685,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); > > is this safe? You're doing this after request_thr