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>
This commit is contained in:
		
							parent
							
								
									3922fb46f0
								
							
						
					
					
						commit
						cf40b86b6e
					
				| @ -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: | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
| 	if (dwc->imod_interval) { | ||||
| 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB); | ||||
| 		dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval); | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user