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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

John Youn <johnyoun@xxxxxxxxxxxx> 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 <johnyoun@xxxxxxxxxxxx>
> ---
>  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	0xffff0000
>  #define DWC3_GSNPSREV_MASK	0xffff
>  
> @@ -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	(0xffff << 16)
> +#define DWC3_DEV_IMOD_INTERVAL_SHIFT	0
> +#define DWC3_DEV_IMOD_INTERVAL_MASK	(0xffff << 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		0x80000000
>  #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 {
>  
>  	unsigned		tx_de_emphasis_quirk:1;
>  	unsigned		tx_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(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);
>  
> +	if (dwc->imod_interval) {
> +		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);

is this really safe? Aren't you forcefully clearing GEVNTCOUNT back to
zero here?  Why couldn't you do a single write to GEVNTCOUNT?

Waiting for you reply before applying. BTW, I've applied patch 1, but
broke it down into smaller patches. I'll send them to linux-usb shortly.

-- 
balbi

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux