Re: [PATCH v4 2/3] usb: dwc3: Implement interrupt moderation

2016-11-15 Thread John Youn
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 

Re: [PATCH v4 2/3] usb: dwc3: Implement interrupt moderation

2016-11-15 Thread Felipe Balbi

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 

[PATCH v4 2/3] usb: dwc3: Implement interrupt moderation

2016-11-14 Thread John Youn
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,