Re: [PATCH 3/4] usb: dwc3: first part of hibernation support

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

 



Hi,

On Mon, Feb 06, 2012 at 07:20:15PM -0800, Paul Zimmerman wrote:
> This patch modifies the existing driver code to allow hibernation
> support to be added by the next patch in the series. This patch by
> itself should not change the existing functionality.
> 
> This patch adds some new register definitions, exports a few
> previously static functions that will be needed by the hibernation
> code, adds a couple of new functions, refactors a few existing
> functions, and adds some hooks that will be needed. The hooks are
> currently all defined to no-ops in the new "hibernate.h".
> 
> The second part will add the actual hibernation code, and allow it
> to be optionally enabled in the kernel config.
> 
> NOTE: This patch renames dwc3-pci.c to dwc3_pci.c and dwc3-omap.c
> to dwc3_omap.c. This is necessary because the next patch adds a
> new platform-specific file that gets included into the bus glue
> module. But if a source file name is the same as the module name,
> then Kconfig doesn't allow adding other object files to the module.
> Other alternatives would be to change the module name, or to
> include the other source files directly into dwc3-pci.c or
> dwc3-omap.c.
> 
> Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx>

One thing: I need your changes to be a bit more atomic. You shuffle a
bunch of stuff around then add new code all in the same patch. Please
make it easy for reviewers/maintainers and do all cleanups/shuffling
separated from new code ;-)

> diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
> index 900ae74..e37ecd3 100644
> --- a/drivers/usb/dwc3/Makefile
> +++ b/drivers/usb/dwc3/Makefile
> @@ -26,9 +26,11 @@ endif
>  # PCI doesn't provide nops if CONFIG_PCI isn't enabled.
>  ##
>  
> -obj-$(CONFIG_USB_DWC3)		+= dwc3-omap.o
> +obj-$(CONFIG_USB_DWC3)			+= dwc3-omap.o
> +	dwc3-omap-y			:= dwc3_omap.o
>  
>  ifneq ($(CONFIG_PCI),)
>  	obj-$(CONFIG_USB_DWC3)		+= dwc3-pci.o
> -endif
>  
> +	dwc3-pci-y			:= dwc3_pci.o
> +endif
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index f5ffe1c..56f60ef 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -56,6 +56,7 @@
>  
>  #include "core.h"
>  #include "gadget.h"
> +#include "hibernate.h"
>  #include "io.h"
>  
>  #include "debug.h"
> @@ -256,7 +257,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
>   *
>   * Returns 0 on success otherwise negative errno.
>   */
> -static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
> +int dwc3_event_buffers_setup(struct dwc3 *dwc)
>  {
>  	struct dwc3_event_buffer	*evt;
>  	int				n;
> @@ -266,6 +267,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
>  		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
>  				evt->buf, (unsigned long long) evt->dma,
>  				evt->length);
> +		evt->lpos = 0;
>  
>  		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
>  				lower_32_bits(evt->dma));
> @@ -286,6 +288,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
>  
>  	for (n = 0; n < dwc->num_event_buffers; n++) {
>  		evt = dwc->ev_buffs[n];
> +		evt->lpos = 0;
>  		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
>  		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
>  		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
> @@ -306,6 +309,21 @@ static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
>  	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
>  	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
>  	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
> +
> +	if (!dwc3_hiber_enabled(dwc) &&
> +			DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)
> +				== DWC3_GHWPARAMS1_EN_PWROPT_HIB) {
> +		/*
> +		 * If the core supports hibernation, but the user has
> +		 * not enabled it, remove it from the hwparams so we
> +		 * won't try to enable it. But do keep clock gating
> +		 * enabled.
> +		 */
> +		parms->hwparams1 &= ~DWC3_GHWPARAMS1_PWROPT_MASK;
> +		parms->hwparams1 |=
> +			DWC3_GHWPARAMS1_PWROPT(DWC3_GHWPARAMS1_EN_PWROPT_CLK);
> +		dev_dbg(dwc->dev, "Hibernation disabled\n");
> +	}
>  }
>  
>  /**
> @@ -355,8 +373,14 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
>  	reg &= ~DWC3_GCTL_DISSCRAMBLE;
>  
>  	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
> +	case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
> +		if (dwc3_hiber_enabled(dwc)) {
> +			dev_dbg(dwc->dev, "Hibernation enabled\n");
> +			reg |= DWC3_GCTL_GBLHIBERNATIONEN;
> +		}
>  	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
>  		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
> +		dev_dbg(dwc->dev, "Clock gating enabled\n");
>  		break;
>  	default:
>  		dev_dbg(dwc->dev, "No power optimization available\n");
> @@ -373,6 +397,13 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
>  
>  	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
>  
> +	ret = dwc3_alloc_scratchpad_buffers(dwc);
> +	if (ret) {
> +		dev_err(dwc->dev,
> +			"failed to allocate scratchpad buffers\n");
> +		goto err0;
> +	}
> +
>  	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
>  	if (ret) {
>  		dev_err(dwc->dev, "failed to allocate event buffers\n");
> @@ -383,14 +414,15 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
>  	ret = dwc3_event_buffers_setup(dwc);
>  	if (ret) {
>  		dev_err(dwc->dev, "failed to setup event buffers\n");
> -		goto err1;
> +		goto err2;
>  	}
>  
>  	return 0;
>  
> -err1:
> +err2:
>  	dwc3_free_event_buffers(dwc);
> -
> +err1:
> +	dwc3_free_scratchpad_buffers(dwc);
>  err0:
>  	return ret;
>  }
> @@ -399,6 +431,7 @@ static void dwc3_core_exit(struct dwc3 *dwc)
>  {
>  	dwc3_event_buffers_cleanup(dwc);
>  	dwc3_free_event_buffers(dwc);
> +	dwc3_free_scratchpad_buffers(dwc);
>  }
>  
>  #define DWC3_ALIGN_MASK		(16 - 1)
> @@ -610,6 +643,12 @@ static struct platform_driver dwc3_driver = {
>  	},
>  };
>  
> +/* These get filled in by the bus glue code if hibernation is supported */
> +void (*dwc3_power_ctl)(struct dwc3 *dwc, int on);
> +EXPORT_SYMBOL_GPL(dwc3_power_ctl);
> +int (*dwc3_pme_interrupt)(struct dwc3 *dwc);
> +EXPORT_SYMBOL_GPL(dwc3_pme_interrupt);
> +
>  MODULE_ALIAS("platform:dwc3");
>  MODULE_AUTHOR("Felipe Balbi <balbi@xxxxxx>");
>  MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 12c1105..aa5ee23 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -65,6 +65,7 @@
>  #define DWC3_DEVICE_EVENT_CONNECT_DONE		2
>  #define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
>  #define DWC3_DEVICE_EVENT_WAKEUP		4
> +#define DWC3_DEVICE_EVENT_HIBER_REQ		5
>  #define DWC3_DEVICE_EVENT_EOPF			6
>  #define DWC3_DEVICE_EVENT_SOF			7
>  #define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
> @@ -159,28 +160,36 @@
>  #define DWC3_GCTL_PRTCAP_DEVICE	2
>  #define DWC3_GCTL_PRTCAP_OTG	3
>  
> -#define DWC3_GCTL_CORESOFTRESET	(1 << 11)
> -#define DWC3_GCTL_SCALEDOWN(n)	((n) << 4)
> -#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
> -#define DWC3_GCTL_DISSCRAMBLE	(1 << 3)
> -#define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
> +#define DWC3_GCTL_CORESOFTRESET		(1 << 11)
> +#define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)
> +#define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)
> +#define DWC3_GCTL_DISSCRAMBLE		(1 << 3)
> +#define DWC3_GCTL_GBLHIBERNATIONEN	(1 << 1)
> +#define DWC3_GCTL_DSBLCLKGTNG		(1 << 0)
>  
>  /* Global USB2 PHY Configuration Register */
> -#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
> -#define DWC3_GUSB2PHYCFG_SUSPHY	(1 << 6)
> +#define DWC3_GUSB2PHYCFG_PHYSOFTRST	(1 << 31)
> +#define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
>  
>  /* Global USB3 PIPE Control Register */
> -#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
> -#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
> +#define DWC3_GUSB3PIPECTL_PHYSOFTRST	(1 << 31)
> +#define DWC3_GUSB3PIPECTL_SUSPHY	(1 << 17)
>  
>  /* Global TX Fifo Size Register */
> -#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
> -#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
> +#define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
> +#define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
>  
>  /* Global HWPARAMS1 Register */
>  #define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
>  #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
>  #define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
> +#define DWC3_GHWPARAMS1_EN_PWROPT_HIB	2
> +#define DWC3_GHWPARAMS1_PWROPT(n)	((n) << 24)
> +#define DWC3_GHWPARAMS1_PWROPT_MASK	DWC3_GHWPARAMS1_PWROPT(3)
> +
> +/* Global HWPARAMS4 Register */
> +#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n)	(((n) & (0x0f << 13)) >> 13)
> +#define DWC3_MAX_HIBER_SCRATCHBUFS		15
>  
>  /* Device Configuration Register */
>  #define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
> @@ -193,6 +202,8 @@
>  #define DWC3_DCFG_LOWSPEED	(2 << 0)
>  #define DWC3_DCFG_FULLSPEED1	(3 << 0)
>  
> +#define DWC3_DCFG_LPM_CAP	(1 << 22)
> +
>  /* Device Control Register */
>  #define DWC3_DCTL_RUN_STOP	(1 << 31)
>  #define DWC3_DCTL_CSFTRST	(1 << 30)
> @@ -203,14 +214,20 @@
>  
>  #define DWC3_DCTL_APPL1RES	(1 << 23)
>  
> -#define DWC3_DCTL_TRGTULST_MASK	(0x0f << 17)
> -#define DWC3_DCTL_TRGTULST(n)	((n) << 17)
> -
> -#define DWC3_DCTL_TRGTULST_U2	(DWC3_DCTL_TRGTULST(2))
> -#define DWC3_DCTL_TRGTULST_U3	(DWC3_DCTL_TRGTULST(3))
> -#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
> -#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
> -#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
> +/* These apply for core versions 1.87a and earlier */
> +#define DWC3_DCTL_TRGTULST_MASK		(0x0f << 17)
> +#define DWC3_DCTL_TRGTULST(n)		((n) << 17)
> +#define DWC3_DCTL_TRGTULST_U2		(DWC3_DCTL_TRGTULST(2))
> +#define DWC3_DCTL_TRGTULST_U3		(DWC3_DCTL_TRGTULST(3))
> +#define DWC3_DCTL_TRGTULST_SS_DIS	(DWC3_DCTL_TRGTULST(4))
> +#define DWC3_DCTL_TRGTULST_RX_DET	(DWC3_DCTL_TRGTULST(5))
> +#define DWC3_DCTL_TRGTULST_SS_INACT	(DWC3_DCTL_TRGTULST(6))
> +
> +/* These apply for core versions 1.94a and later */
> +#define DWC3_DCTL_KEEP_CONNECT	(1 << 19)
> +#define DWC3_DCTL_L1_HIBER_EN	(1 << 18)
> +#define DWC3_DCTL_CRS		(1 << 17)
> +#define DWC3_DCTL_CSS		(1 << 16)
>  
>  #define DWC3_DCTL_INITU2ENA	(1 << 12)
>  #define DWC3_DCTL_ACCEPTU2ENA	(1 << 11)
> @@ -236,6 +253,7 @@
>  #define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
>  #define DWC3_DEVTEN_SOFEN		(1 << 7)
>  #define DWC3_DEVTEN_EOPFEN		(1 << 6)
> +#define DWC3_DEVTEN_HIBERNATIONREQEVTEN	(1 << 5)
>  #define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
>  #define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
>  #define DWC3_DEVTEN_CONNECTDONEEN	(1 << 2)
> @@ -243,7 +261,15 @@
>  #define DWC3_DEVTEN_DISCONNEVTEN	(1 << 0)
>  
>  /* Device Status Register */
> +#define DWC3_DSTS_DCNRD			(1 << 29)
> +
> +/* This applies for core versions 1.87a and earlier */
>  #define DWC3_DSTS_PWRUPREQ		(1 << 24)
> +
> +/* These apply for core versions 1.94a and later */
> +#define DWC3_DSTS_RSS			(1 << 25)
> +#define DWC3_DSTS_SSS			(1 << 24)
> +
>  #define DWC3_DSTS_COREIDLE		(1 << 23)
>  #define DWC3_DSTS_DEVCTRLHLT		(1 << 22)
>  
> @@ -264,13 +290,31 @@
>  #define DWC3_DSTS_FULLSPEED1		(3 << 0)
>  
>  /* Device Generic Command Register */
> -#define DWC3_DGCMD_SET_LMP		0x01
> -#define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
> -#define DWC3_DGCMD_XMIT_FUNCTION	0x03
> -#define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
> -#define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
> -#define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
> -#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
> +#define DWC3_DGCMD_STATUS_MASK		(0x0f << 12)
> +#define DWC3_DGCMD_STATUS(x)		(((x) & DWC3_DGCMD_STATUS_MASK) >> 12)
> +#define DWC3_DGCMD_CMDACT		(1 << 10)
> +#define DWC3_DGCMD_CMDIOC		(1 << 8)
> +
> +#define DWC3_DGCMD_SET_LMP			0x01
> +#define DWC3_DGCMD_SET_PERIODIC_PAR		0x02
> +#define DWC3_DGCMD_XMIT_FUNCTION		0x03
> +
> +/* These apply for core versions 1.94a and later */
> +#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO	0x04
> +#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI	0x05
> +
> +#define DWC3_DGCMD_SELECTED_FIFO_FLUSH		0x09
> +#define DWC3_DGCMD_ALL_FIFO_FLUSH		0x0a
> +#define DWC3_DGCMD_SET_ENDPOINT_NRDY		0x0c
> +#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK		0x10
> +
> +/* Device Generic Command Parameter Register */
> +#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT	(1 << 0)
> +#define DWC3_DGCMDPAR_FIFO_NUM(n)		((n) << 0)
> +#define DWC3_DGCMDPAR_RX_FIFO			(0 << 5)
> +#define DWC3_DGCMDPAR_TX_FIFO			(1 << 5)
> +#define DWC3_DGCMDPAR_LOOPBACK_DIS		(0 << 0)
> +#define DWC3_DGCMDPAR_LOOPBACK_ENA		(1 << 0)
>  
>  /* Device Endpoint Command Register */
>  #define DWC3_DEPCMD_PARAM_SHIFT		16
> @@ -288,7 +332,10 @@
>  #define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
>  #define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
>  #define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
> +/* This applies for core versions 1.90a and earlier */
>  #define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
> +/* This applies for core versions 1.94a and later */
> +#define DWC3_DEPCMD_GETEPSTATE		(0x03 << 0)
>  #define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
>  #define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)

all register modifications could be part of their own patch ;-) for
example.

>  
> @@ -381,6 +428,11 @@ struct dwc3_ep {
>  	u8			type;
>  	u8			res_trans_idx;
>  	u32			interval;
> +	u32			saved_state;
> +
> +#ifdef CONFIG_USB_DWC3_HIBERNATION
> +	int			hiber_trb_idx;
> +#endif

and this doesn't belong here, it should probably be added when you _do_
add hibernation.

> @@ -423,6 +475,8 @@ enum dwc3_link_state {
>  	DWC3_LINK_STATE_HRESET		= 0x09,
>  	DWC3_LINK_STATE_CMPLY		= 0x0a,
>  	DWC3_LINK_STATE_LPBK		= 0x0b,
> +	DWC3_LINK_STATE_RESET		= 0x0e,
> +	DWC3_LINK_STATE_RESUME		= 0x0f,
>  	DWC3_LINK_STATE_MASK		= 0x0f,
>  };
>  
> @@ -472,6 +526,7 @@ struct dwc3_trb {
>  #define DWC3_TRB_STS_OKAY			0
>  #define DWC3_TRB_STS_MISSED_ISOC		1
>  #define DWC3_TRB_STS_SETUP_PENDING		2
> +#define DWC3_TRB_STS_XFER_IN_PROG		4

ahaa, new status. This, while small, deserves its own patch. On the
commit log you could note which version of the core added this extra
status.

> @@ -582,6 +637,14 @@ struct dwc3_request {
>  	unsigned		queued:1;
>  };
>  
> +/*
> + * struct dwc3_scratchpad_array - hibernation scratchpad array
> + * (format defined by hw)
> + */
> +struct dwc3_scratchpad_array {
> +	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];

make it dma_addr. BTW, couldn't this be a dma_addr_t instead of __le64 ?

> @@ -662,8 +725,10 @@ struct dwc3 {
>  #define DWC3_REVISION_180A	0x5533180a
>  #define DWC3_REVISION_183A	0x5533183a
>  #define DWC3_REVISION_185A	0x5533185a
> +#define DWC3_REVISION_187A	0x5533187a
>  #define DWC3_REVISION_188A	0x5533188a
>  #define DWC3_REVISION_190A	0x5533190a
> +#define DWC3_REVISION_194A	0x5533194a

also separate patch. I don't remember seeing these releases on your
support site...

> @@ -675,6 +740,33 @@ struct dwc3 {
>  	unsigned		needs_fifo_resize:1;
>  	unsigned		resize_fifos:1;
>  
> +#ifdef CONFIG_USB_DWC3_HIBERNATION
> +	unsigned		hiber_wait_connect:1;
> +	unsigned		hiber_wait_u0:1;
> +
> +	int			hibernate;
> +#define DWC3_HIBER_AWAKE	0
> +#define DWC3_HIBER_ENTER_NOSAVE	1
> +#define DWC3_HIBER_ENTER_SAVE	2
> +#define DWC3_HIBER_SLEEPING	3
> +#define DWC3_HIBER_WAIT_LINK_UP	4
> +#define DWC3_HIBER_SS_DIS_QUIRK	5
> +
> +	int			pme_ready;
> +	int			usage_cnt;
> +
> +	struct task_struct	*hiber_thread;
> +	struct dwc3_scratchpad_array *scratchpad_array;
> +	dma_addr_t		scratchpad_array_dma;
> +	void			*scratchpad[DWC3_MAX_HIBER_SCRATCHBUFS];
> +
> +	u32			gctl_save;
> +	u32			dcfg_save;
> +	u32			dctl_save;
> +	u32			rxfifosz_save;
> +	u32			txfifosz_save[DWC3_ENDPOINTS_NUM / 2];
> +#endif

I would rather have a separate structure altogether. Please define a
struct dwc3_context or something and just hold a pointer for it here. Of
course, allocate the pointer on probe(). Then you could also remove the
ifdef, because you can decide in runtime if you allocate memory or not.

> @@ -843,7 +935,12 @@ void dwc3_host_exit(struct dwc3 *dwc);
>  int dwc3_gadget_init(struct dwc3 *dwc);
>  void dwc3_gadget_exit(struct dwc3 *dwc);
>  
> -extern int dwc3_get_device_id(void);
> -extern void dwc3_put_device_id(int id);
> +int dwc3_get_device_id(void);
> +void dwc3_put_device_id(int id);
> +int dwc3_event_buffers_setup(struct dwc3 *dwc);

removing the extern is also part of a separate patch.

(Yeah, quite anal... but 3 years from now when I need to refresh my
memory of  why a certain change was made, this will pay off)

> diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3_omap.c
> similarity index 99%
> rename from drivers/usb/dwc3/dwc3-omap.c
> rename to drivers/usb/dwc3/dwc3_omap.c
> index 64e29c3..c422dfb 100644
> --- a/drivers/usb/dwc3/dwc3-omap.c
> +++ b/drivers/usb/dwc3/dwc3_omap.c
> @@ -1,5 +1,5 @@
>  /**
> - * dwc3-omap.c - OMAP Specific Glue layer
> + * dwc3_omap.c - OMAP Specific Glue layer
>   *
>   * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
>   *
> diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3_pci.c
> similarity index 94%
> rename from drivers/usb/dwc3/dwc3-pci.c
> rename to drivers/usb/dwc3/dwc3_pci.c
> index 64e1f7c..d630fac 100644
> --- a/drivers/usb/dwc3/dwc3-pci.c
> +++ b/drivers/usb/dwc3/dwc3_pci.c
> @@ -1,5 +1,5 @@
>  /**
> - * dwc3-pci.c - PCI Specific glue layer
> + * dwc3_pci.c - PCI Specific glue layer
>   *
>   * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
>   *
> @@ -43,8 +43,8 @@
>  #include <linux/platform_device.h>
>  
>  #include "core.h"
> +#include "haps_pwrctl.h"

I don't like this. It couples dwc3-pci with HAPS and we all know this
file will be (is ?) used with platforms other than HAPS.

> @@ -106,6 +106,12 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
>  		goto err4;
>  	}
>  
> +	if (pci->vendor == PCI_VENDOR_ID_SYNOPSYS &&
> +			pci->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3) {
> +		dwc3_power_ctl = dwc3_haps_power_ctl;
> +		dwc3_pme_interrupt = dwc3_haps_pme_intr;
> +	}

another way, which would be neater, would be to pass this as
driver_data. But I want to avoid needing this, I need to read patch 4/4
first, though.

> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index 4702b75..accf876 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -52,6 +52,7 @@
>  
>  #include "core.h"
>  #include "gadget.h"
> +#include "hibernate.h"
>  #include "io.h"
>  
>  #define DMA_ADDR_INVALID	(~(dma_addr_t)0)
> @@ -90,6 +91,38 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
>  }
>  
>  /**
> + * dwc3_gadget_get_link_state - Gets current state of USB Link
> + * @dwc: pointer to our context structure
> + * @state: the state to put link into
> + *
> + * Caller should take care of locking. This function will
> + * return current link state on success or -ETIMEDOUT.
> + */
> +int dwc3_gadget_get_link_state(struct dwc3 *dwc)
> +{
> +	int		retries = 10000;
> +	u32		reg;
> +
> +	/*
> +	 * Wait until device controller is ready. Only applies to 1.94a and
> +	 * later RTL. This will succeed immediately on pre-1.94a because the
> +	 * undefined register bits are hardwired to 0.
> +	 */

if it only applies to 1.94a+ you ought to add a revision check and
return early otherwise. Something like:

if (dwc->revision < DWC3_REVISION_194A)
	goto out;

the thing with those reserved bits is that you never know when someone
screws up and the reserved stop returning 0 ;-) I'd be happier with the
check above.

> +	while (--retries) {
> +		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
> +		if (reg & DWC3_DSTS_DCNRD)
> +			udelay(5);
> +		else
> +			break;
> +	}
> +
> +	if (retries <= 0)
> +		return -ETIMEDOUT;
> +

out:

> +	return DWC3_DSTS_USBLNKST(reg);
> +}
> +
> +/**
>   * dwc3_gadget_set_link_state - Sets USB Link to a particular State
>   * @dwc: pointer to our context structure
>   * @state: the state to put link into
> @@ -102,6 +135,22 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
>  	int		retries = 10000;
>  	u32		reg;
>  
> +	/*
> +	 * Wait until device controller is ready. Only applies to 1.94a and
> +	 * later RTL. This will succeed immediately on pre-1.94a because the
> +	 * undefined register bits are hardwired to 0.
> +	 */

likewise.

> +	while (--retries) {
> +		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
> +		if (reg & DWC3_DSTS_DCNRD)
> +			udelay(5);
> +		else
> +			break;
> +	}
> +
> +	if (retries <= 0)
> +		return -ETIMEDOUT;
> +
>  	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
>  	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
>  
> @@ -109,7 +158,11 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
>  	reg |= DWC3_DCTL_ULSTCHNGREQ(state);
>  	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
>  
> +	if (dwc->revision >= DWC3_REVISION_194A)
> +		return 0;
> +
>  	/* wait for a change in DSTS */
> +	retries = 10000;
>  	while (--retries) {
>  		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
>  
> @@ -312,8 +365,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
>  		return "Clear Stall";
>  	case DWC3_DEPCMD_SETSTALL:
>  		return "Set Stall";
> -	case DWC3_DEPCMD_GETSEQNUMBER:
> -		return "Get Data Sequence Number";
> +	case DWC3_DEPCMD_GETEPSTATE:
> +		return "Get Endpoint State";

Now we're screwed :-) If we're running on an older core and we want to
send GETSEQNUMBER, debugging message will be wrong. You will need to add
a revision check here. So pass struct dwc3 as a parameter too, I guess
it's the only way.

> @@ -360,6 +413,63 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
>  	} while (1);
>  }
>  
> +static const char *dwc3_gadget_dev_cmd_string(u8 cmd)
> +{
> +	switch (cmd) {
> +	case DWC3_DGCMD_SET_LMP:
> +		return "Transmit Set Link Function LMP";
> +	case DWC3_DGCMD_SET_PERIODIC_PAR:
> +		return "Set Periodic Parameters";
> +	case DWC3_DGCMD_XMIT_FUNCTION:
> +		return "Transmit Function Wake Device Notification";
> +	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO:
> +		return "Set Scratchpad Buffer Array Address Lo";
> +	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI:
> +		return "Set Scratchpad Buffer Array Address Hi";
> +	case DWC3_DGCMD_SELECTED_FIFO_FLUSH:
> +		return "Selected FIFO Flush";
> +	case DWC3_DGCMD_ALL_FIFO_FLUSH:
> +		return "All FIFO Flush";
> +	case DWC3_DGCMD_SET_ENDPOINT_NRDY:
> +		return "Set Endpoint NRDY";
> +	case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK:
> +		return "Run SoC Bus LoopBack Test";
> +	default:
> +		return "UNKNOWN command";
> +	}
> +}
> +
> +int dwc3_send_gadget_dev_cmd(struct dwc3 *dwc, unsigned cmd, u32 param)
> +{
> +	u32			timeout = 500;
> +	u32			reg;
> +
> +	dev_vdbg(dwc->dev, "%s: cmd '%s' param %08x\n", __func__,
> +			dwc3_gadget_dev_cmd_string(cmd), param);
> +
> +	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
> +
> +	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
> +	do {
> +		reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
> +		if (!(reg & DWC3_DGCMD_CMDACT)) {
> +			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
> +					DWC3_DGCMD_STATUS(reg));
> +			return 0;
> +		}
> +
> +		/*
> +		 * We can't sleep here, because it is also called from
> +		 * interrupt context.
> +		 */
> +		timeout--;
> +		if (!timeout)
> +			return -ETIMEDOUT;
> +
> +		udelay(1);
> +	} while (1);
> +}
> +
>  static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
>  		struct dwc3_trb_hw *trb)
>  {
> @@ -426,7 +536,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
>  
>  static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
>  		const struct usb_endpoint_descriptor *desc,
> -		const struct usb_ss_ep_comp_descriptor *comp_desc)
> +		const struct usb_ss_ep_comp_descriptor *comp_desc,
> +		bool restore)
>  {
>  	struct dwc3_gadget_ep_cmd_params params;
>  
> @@ -468,6 +579,11 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
>  		dep->interval = 1 << (desc->bInterval - 1);
>  	}
>  
> +	if (restore) {
> +		params.param0 |= DWC3_DEPCFG_ACTION_RESTORE;
> +		params.param2 = dep->saved_state;
> +	}
> +
>  	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
>  			DWC3_DEPCMD_SETEPCONFIG, &params);
>  }
> @@ -491,9 +607,10 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
>   *
>   * Caller should take care of locking
>   */
> -static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
> +int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
>  		const struct usb_endpoint_descriptor *desc,
> -		const struct usb_ss_ep_comp_descriptor *comp_desc)
> +		const struct usb_ss_ep_comp_descriptor *comp_desc,
> +		bool restore)
>  {
>  	struct dwc3		*dwc = dep->dwc;
>  	u32			reg;
> @@ -505,7 +622,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
>  			return ret;
>  	}
>  
> -	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
> +	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, restore);
>  	if (ret)
>  		return ret;
>  
> @@ -546,13 +663,12 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
>  	return 0;
>  }
>  
> -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
>  static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
>  {
>  	struct dwc3_request		*req;
>  
>  	if (!list_empty(&dep->req_queued))
> -		dwc3_stop_active_transfer(dwc, dep->number);
> +		dwc3_stop_active_transfer(dwc, dep->number, true);
>  
>  	while (!list_empty(&dep->request_list)) {
>  		req = next_request(&dep->request_list);
> @@ -651,7 +767,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
>  	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
>  
>  	spin_lock_irqsave(&dwc->lock, flags);
> -	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);
> +	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return ret;
> @@ -1071,6 +1187,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
>  	int				ret = 0;
>  
>  	spin_lock_irqsave(&dwc->lock, flags);
> +	dwc3_wait_if_hibernating(dwc, flags);
> +	dwc3_gadget_get_ctlr(dwc);
>  
>  	list_for_each_entry(r, &dep->request_list, list) {
>  		if (r == req)
> @@ -1084,7 +1202,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
>  		}
>  		if (r == req) {
>  			/* wait until it is processed */
> -			dwc3_stop_active_transfer(dwc, dep->number);
> +			dwc3_stop_active_transfer(dwc, dep->number, true);
>  			goto out0;
>  		}
>  		dev_err(dwc->dev, "request %p was not queued to %s\n",
> @@ -1097,6 +1215,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
>  	dwc3_gadget_giveback(dep, req, -ECONNRESET);
>  
>  out0:
> +	dwc3_gadget_put_ctlr(dwc);
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return ret;
> @@ -1155,6 +1274,8 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
>  	int				ret;
>  
>  	spin_lock_irqsave(&dwc->lock, flags);
> +	dwc3_wait_if_hibernating(dwc, flags);
> +	dwc3_gadget_get_ctlr(dwc);
>  
>  	if (usb_endpoint_xfer_isoc(dep->desc)) {
>  		dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
> @@ -1164,6 +1285,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
>  
>  	ret = __dwc3_gadget_ep_set_halt(dep, value);
>  out:
> +	dwc3_gadget_put_ctlr(dwc);
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return ret;
> @@ -1184,7 +1306,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
>  
>  /* -------------------------------------------------------------------------- */
>  
> -static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
> +struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {

where are you accessing this from ? This should really not be visible
outside of this file. This needs to be a separate patch, btw.

> @@ -1238,6 +1360,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
>  	u8			speed;
>  
>  	spin_lock_irqsave(&dwc->lock, flags);
> +	dwc3_wait_if_hibernating(dwc, flags);
> +	dwc3_gadget_get_ctlr(dwc);
>  
>  	/*
>  	 * According to the Databook Remote wakeup request should
> @@ -1273,9 +1397,11 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
>  		goto out;
>  	}
>  
> -	/* write zeroes to Link Change Request */
> -	reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
> -	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
> +	if (dwc->revision < DWC3_REVISION_194A) {
> +		/* write zeroes to Link Change Request */
> +		reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
> +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
> +	}

separate patch.

> @@ -1298,6 +1424,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
>  	}
>  
>  out:
> +	dwc3_gadget_put_ctlr(dwc);
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return ret;
> @@ -1316,16 +1443,23 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
>  	return 0;
>  }
>  
> -static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
> +void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)

this is also a gadget specific API, shouldn't be visible outside of
gadget.c

>  {
>  	u32			reg;
>  	u32			timeout = 500;
>  
>  	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
>  	if (is_on) {
> -		reg &= ~DWC3_DCTL_TRGTULST_MASK;
> -		reg |= (DWC3_DCTL_RUN_STOP
> -				| DWC3_DCTL_TRGTULST_RX_DET);
> +		if (dwc->revision <= DWC3_REVISION_187A) {
> +			reg &= ~DWC3_DCTL_TRGTULST_MASK;
> +			reg |= DWC3_DCTL_TRGTULST_RX_DET;
> +		}
> +		reg |= DWC3_DCTL_RUN_STOP;
> +
> +		if (dwc3_hiber_enabled(dwc))
> +			reg |= DWC3_DCTL_KEEP_CONNECT;
> +		else
> +			reg &= ~DWC3_DCTL_KEEP_CONNECT;
>  	} else {
>  		reg &= ~DWC3_DCTL_RUN_STOP;
>  	}
> @@ -1361,53 +1495,35 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
>  	is_on = !!is_on;
>  
>  	spin_lock_irqsave(&dwc->lock, flags);
> +	dwc3_wait_if_hibernating(dwc, flags);
> +	dwc3_gadget_get_ctlr(dwc);
> +
>  	dwc3_gadget_run_stop(dwc, is_on);
> +
> +	dwc3_gadget_put_ctlr(dwc);
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return 0;
>  }
>  
> -static int dwc3_gadget_start(struct usb_gadget *g,
> -		struct usb_gadget_driver *driver)
> +int __dwc3_gadget_start(struct dwc3 *dwc, bool restore)
>  {
> -	struct dwc3		*dwc = gadget_to_dwc(g);
> -	struct dwc3_ep		*dep;
> -	unsigned long		flags;
> -	int			ret = 0;
> -	u32			reg;
> -
> -	spin_lock_irqsave(&dwc->lock, flags);
> -
> -	if (dwc->gadget_driver) {
> -		dev_err(dwc->dev, "%s is already bound to %s\n",
> -				dwc->gadget.name,
> -				dwc->gadget_driver->driver.name);
> -		ret = -EBUSY;
> -		goto err0;
> -	}
> -
> -	dwc->gadget_driver	= driver;
> -	dwc->gadget.dev.driver	= &driver->driver;
> -
> -	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
> -	reg &= ~(DWC3_DCFG_SPEED_MASK);
> -	reg |= dwc->maximum_speed;
> -	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
> +	struct dwc3_ep	*dep;
> +	int		ret;
>  
>  	dwc->start_config_issued = false;
>  
> -	/* Start with SuperSpeed Default */
> -	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
> -
>  	dep = dwc->eps[0];
> -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
> +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL,
> +					restore);
>  	if (ret) {
>  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
>  		goto err0;
>  	}
>  
>  	dep = dwc->eps[1];
> -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
> +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL,
> +					restore);
>  	if (ret) {
>  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
>  		goto err1;
> @@ -1417,14 +1533,48 @@ static int dwc3_gadget_start(struct usb_gadget *g,
>  	dwc->ep0state = EP0_SETUP_PHASE;
>  	dwc3_ep0_out_start(dwc);
>  
> -	spin_unlock_irqrestore(&dwc->lock, flags);
> -
>  	return 0;
>  
>  err1:
>  	__dwc3_gadget_ep_disable(dwc->eps[0]);
> -
>  err0:
> +	return ret;
> +}
> +
> +static int dwc3_gadget_start(struct usb_gadget *g,
> +		struct usb_gadget_driver *driver)
> +{
> +	struct dwc3		*dwc = gadget_to_dwc(g);
> +	unsigned long		flags;
> +	u32			reg;
> +	int			ret;
> +
> +	spin_lock_irqsave(&dwc->lock, flags);
> +	dwc3_wait_if_hibernating(dwc, flags);
> +	dwc3_gadget_get_ctlr(dwc);
> +
> +	if (dwc->gadget_driver) {
> +		dev_err(dwc->dev, "%s is already bound to %s\n",
> +				dwc->gadget.name,
> +				dwc->gadget_driver->driver.name);
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	dwc->gadget_driver	= driver;
> +	dwc->gadget.dev.driver	= &driver->driver;
> +
> +	/* Start with SuperSpeed Default */
> +	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
> +
> +	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
> +	reg &= ~(DWC3_DCFG_SPEED_MASK);
> +	reg |= dwc->maximum_speed;
> +	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
> +
> +	ret = __dwc3_gadget_start(dwc, false);
> +out:
> +	dwc3_gadget_put_ctlr(dwc);
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return ret;
> @@ -1437,6 +1587,8 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
>  	unsigned long		flags;
>  
>  	spin_lock_irqsave(&dwc->lock, flags);
> +	dwc3_wait_if_hibernating(dwc, flags);
> +	dwc3_gadget_get_ctlr(dwc);
>  
>  	__dwc3_gadget_ep_disable(dwc->eps[0]);
>  	__dwc3_gadget_ep_disable(dwc->eps[1]);
> @@ -1444,10 +1596,12 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
>  	dwc->gadget_driver	= NULL;
>  	dwc->gadget.dev.driver	= NULL;
>  
> +	dwc3_gadget_put_ctlr(dwc);
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return 0;
>  }
> +
>  static const struct usb_gadget_ops dwc3_gadget_ops = {
>  	.get_frame		= dwc3_gadget_get_frame,
>  	.wakeup			= dwc3_gadget_wakeup,
> @@ -1794,7 +1948,7 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)
>  	}
>  }
>  
> -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
> +void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
>  {
>  	struct dwc3_ep *dep;
>  	struct dwc3_gadget_ep_cmd_params params;
> @@ -1803,10 +1957,14 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
>  
>  	dep = dwc->eps[epnum];
>  
> -	WARN_ON(!dep->res_trans_idx);
> -	if (dep->res_trans_idx) {
> +	if (epnum != 0)
> +		WARN_ON(!dep->res_trans_idx);
> +
> +	if (dep->res_trans_idx || epnum == 0) {
>  		cmd = DWC3_DEPCMD_ENDTRANSFER;
> -		cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
> +		if (force)
> +			cmd |= DWC3_DEPCMD_HIPRI_FORCERM;

you have added this new parameter, so it should be a separate patch with
a good reasoning ;-)

> @@ -1875,32 +2033,35 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
>  
>  	dwc->gadget.speed = USB_SPEED_UNKNOWN;
>  	dwc->setup_packet_pending = false;
> +
> +	/* Tell kernel thread to enter hibernation */
> +	dwc3_enter_hiber_nosave(dwc);
>  }
>  
> -static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
> +static void dwc3_gadget_usb3_ena_phy_susp(struct dwc3 *dwc, int enable)

here you're just changing the argument name. Looks unnecessary to me,
but it should be a separate patch.

>  {
>  	u32			reg;
>  
>  	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
>  
> -	if (on)
> -		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
> -	else
> +	if (enable)
>  		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
> +	else
> +		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
>  
>  	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
>  }
>  
> -static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
> +static void dwc3_gadget_usb2_ena_phy_susp(struct dwc3 *dwc, int enable)

hehe, why ? Please revert this rename.

>  {
>  	u32			reg;
>  
>  	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
>  
> -	if (on)
> -		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
> -	else
> +	if (enable)
>  		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
> +	else
> +		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
>  
>  	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
>  }
> @@ -1945,9 +2106,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
>  	/* after reset -> Default State */
>  	dwc->dev_state = DWC3_DEFAULT_STATE;
>  
> -	/* Enable PHYs */
> -	dwc3_gadget_usb2_phy_power(dwc, true);
> -	dwc3_gadget_usb3_phy_power(dwc, true);
> +	/* Recent versions support automatic phy suspend and don't need this */
> +	if (dwc->revision < DWC3_REVISION_194A) {

this is part of a separate patch.

> +		/* Enable PHYs */
> +		dwc3_gadget_usb2_ena_phy_susp(dwc, false);
> +		dwc3_gadget_usb3_ena_phy_susp(dwc, false);
> +	}
>  
>  	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
>  		dwc3_disconnect_gadget(dwc);
> @@ -1991,21 +2155,21 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
>  	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
>  }
>  
> -static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
> +static void dwc3_gadget_suspend_phy(struct dwc3 *dwc, u8 speed)

please revert the rename.

>  {
>  	switch (speed) {
>  	case USB_SPEED_SUPER:
> -		dwc3_gadget_usb2_phy_power(dwc, false);
> +		dwc3_gadget_usb2_ena_phy_susp(dwc, true);
>  		break;
>  	case USB_SPEED_HIGH:
>  	case USB_SPEED_FULL:
>  	case USB_SPEED_LOW:
> -		dwc3_gadget_usb3_phy_power(dwc, false);
> +		dwc3_gadget_usb3_ena_phy_susp(dwc, true);
>  		break;
>  	}
>  }
>  
> -static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
> +void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)

why connection done interrupt handler needs to be visible outside ?

> @@ -2063,18 +2227,21 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
>  		break;
>  	}
>  
> -	/* Disable unneded PHY */
> -	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
> +	/* Recent versions support automatic phy suspend and don't need this */
> +	if (dwc->revision < DWC3_REVISION_194A) {
> +		/* Disable unneeded PHY */
> +		dwc3_gadget_suspend_phy(dwc, dwc->gadget.speed);
> +	}

together with the phy change above.

> @@ -2101,10 +2274,21 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
>  	dwc->gadget_driver->resume(&dwc->gadget);
>  }
>  
> +static void dwc3_gadget_hiber_interrupt(struct dwc3 *dwc,
> +		unsigned int evtinfo)
> +{
> +	dev_vdbg(dwc->dev, "%s\n", __func__);
> +
> +	/* Tell kernel thread to save state and enter hibernation */

why do you need a kthread ?

> +	dwc3_enter_hiber_save(dwc);
> +}
> +
>  static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
>  		unsigned int evtinfo)
>  {
>  	enum dwc3_link_state	next = evtinfo & DWC3_LINK_STATE_MASK;
> +	u32			reg;
> +	u8			speed;
>  
>  	/*
>  	 * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
> @@ -2152,6 +2336,13 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
>  		}
>  	}
>  
> +	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
> +	speed = reg & DWC3_DSTS_CONNECTSPD;
> +	dwc->speed = speed;
> +
> +	/* do hibernation remote wake if needed */
> +	dwc3_hiber_remote_wake(dwc);
> +
>  	dwc->link_state = next;
>  
>  	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
> @@ -2173,6 +2364,9 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
>  	case DWC3_DEVICE_EVENT_WAKEUP:
>  		dwc3_gadget_wakeup_interrupt(dwc);
>  		break;
> +	case DWC3_DEVICE_EVENT_HIBER_REQ:
> +		dwc3_gadget_hiber_interrupt(dwc, event->event_info);
> +		break;
>  	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
>  		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
>  		break;
> @@ -2253,11 +2447,16 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
>  static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
>  {
>  	struct dwc3			*dwc = _dwc;
> +	irqreturn_t			ret;
>  	int				i;
> -	irqreturn_t			ret = IRQ_NONE;
>  
>  	spin_lock(&dwc->lock);
>  
> +	/* If in hibernation, we must not touch the hardware */
> +	ret = dwc3_hiber_interrupt_hook(dwc);
> +	if (ret != IRQ_NONE)
> +		goto out;
> +
>  	for (i = 0; i < dwc->num_event_buffers; i++) {
>  		irqreturn_t status;
>  
> @@ -2265,7 +2464,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
>  		if (status == IRQ_HANDLED)
>  			ret = status;
>  	}
> -
> +out:
>  	spin_unlock(&dwc->lock);
>  
>  	return ret;
> @@ -2351,7 +2550,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
>  	}
>  
>  	/* Enable all but Start and End of Frame IRQs */
> -	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
> +	reg = DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
>  			DWC3_DEVTEN_EVNTOVERFLOWEN |
>  			DWC3_DEVTEN_CMDCMPLTEN |
>  			DWC3_DEVTEN_ERRTICERREN |
> @@ -2359,27 +2558,65 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
>  			DWC3_DEVTEN_ULSTCNGEN |
>  			DWC3_DEVTEN_CONNECTDONEEN |
>  			DWC3_DEVTEN_USBRSTEN |
> -			DWC3_DEVTEN_DISCONNEVTEN);
> +			DWC3_DEVTEN_DISCONNEVTEN;

well, I happen to like my parenthesis :-) And there's no aparent reason
to remove then. The compiler will convert all of that to an integer
anyway.

> +	if (dwc3_hiber_enabled(dwc))
> +		reg |= DWC3_DEVTEN_HIBERNATIONREQEVTEN;
> +
>  	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
>  
> +	/* Reset device address to zero */
> +	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
> +	reg &= ~DWC3_DCFG_DEVADDR_MASK;
> +
> +	/* Enable USB2 LPM only on recent versions */
> +	if (dwc->revision >= DWC3_REVISION_194A)
> +		reg |= DWC3_DCFG_LPM_CAP;

hibernation isn't LPM, right ? So you should split those patches.

> diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
> index 152b6de..a11b054 100644
> --- a/drivers/usb/dwc3/gadget.h
> +++ b/drivers/usb/dwc3/gadget.h
> @@ -66,7 +66,12 @@ struct dwc3;
>  #define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
>  #define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
>  #define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
> +/* This applies for core versions earlier than 1.94a */
>  #define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
> +/* These apply for core versions 1.94a and later */
> +#define DWC3_DEPCFG_ACTION_INIT		(0 << 30)
> +#define DWC3_DEPCFG_ACTION_RESTORE	(1 << 30)
> +#define DWC3_DEPCFG_ACTION_MODIFY	(2 << 30)
>  
>  /* DEPXFERCFG parameter 0 */
>  #define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
> @@ -101,6 +106,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
>  		int status);
>  
>  int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
> +int dwc3_gadget_get_link_state(struct dwc3 *dwc);
>  int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
>  
>  void dwc3_ep0_interrupt(struct dwc3 *dwc,
> @@ -108,11 +114,22 @@ void dwc3_ep0_interrupt(struct dwc3 *dwc,
>  void dwc3_ep0_out_start(struct dwc3 *dwc);
>  int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
>  		gfp_t gfp_flags);
> +int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
> +		const struct usb_endpoint_descriptor *desc,
> +		const struct usb_ss_ep_comp_descriptor *comp_desc,
> +		bool restore);
>  int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
>  int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
>  		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
> +int dwc3_send_gadget_dev_cmd(struct dwc3 *dwc, unsigned cmd, u32 param);
>  void dwc3_map_buffer_to_dma(struct dwc3_request *req);
>  void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
> +void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on);
> +int __dwc3_gadget_start(struct dwc3 *dwc, bool restore);
> +void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
> +void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc);
> +
> +extern struct usb_endpoint_descriptor dwc3_gadget_ep0_desc;
>  
>  /**
>   * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
> diff --git a/drivers/usb/dwc3/haps_pwrctl.h b/drivers/usb/dwc3/haps_pwrctl.h
> new file mode 100644
> index 0000000..b82d356
> --- /dev/null
> +++ b/drivers/usb/dwc3/haps_pwrctl.h
> @@ -0,0 +1,51 @@
> +/**
> + * haps_pwrctl.h - DesignWare USB3 DRD Controller Power Control for HAPS Header
> + *
> + * Copyright (C) 2011-2012 Synopsys Incorporated
> + *
> + * Author: Paul Zimmerman <paulz@xxxxxxxxxxxx>
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions, and the following disclaimer,
> + *    without modification.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The names of the above-listed copyright holders may not be used
> + *    to endorse or promote products derived from this software without
> + *    specific prior written permission.
> + *
> + * ALTERNATIVELY, this software may be distributed under the terms of the
> + * GNU General Public License ("GPL") version 2, as published by the Free
> + * Software Foundation.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include "core.h"
> +
> +#ifdef CONFIG_USB_DWC3_HIBERNATION
> +
> +void dwc3_haps_power_ctl(struct dwc3 *dwc, int on);
> +int dwc3_haps_pme_intr(struct dwc3 *dwc);
> +
> +#else
> +
> +static inline void dwc3_haps_power_ctl(struct dwc3 *dwc3, int on) {}
> +static inline int dwc3_haps_pme_intr(struct dwc3 *dwc)
> +	{ return -1; }
> +
> +#endif
> diff --git a/drivers/usb/dwc3/hibernate.h b/drivers/usb/dwc3/hibernate.h
> new file mode 100644
> index 0000000..e90567b
> --- /dev/null
> +++ b/drivers/usb/dwc3/hibernate.h
> @@ -0,0 +1,126 @@
> +/**
> + * hibernate.h - DesignWare USB3 DRD Controller Hibernation Support Header
> + *
> + * Copyright (C) 2011-2012 Synopsys Incorporated
> + *
> + * Author: Paul Zimmerman <paulz@xxxxxxxxxxxx>
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions, and the following disclaimer,
> + *    without modification.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. The names of the above-listed copyright holders may not be used
> + *    to endorse or promote products derived from this software without
> + *    specific prior written permission.
> + *
> + * ALTERNATIVELY, this software may be distributed under the terms of the
> + * GNU General Public License ("GPL") version 2, as published by the Free
> + * Software Foundation.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
> + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
> + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
> + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
> + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
> + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
> + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifndef __DRIVERS_USB_DWC3_HIBERNATE_H
> +#define __DRIVERS_USB_DWC3_HIBERNATE_H
> +
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/spinlock.h>
> +#include <linux/kthread.h>
> +
> +#ifdef CONFIG_USB_DWC3_HIBERNATION

to be very straight with you, I think this file is hugely unnecessary
and all of this could/should be added to drivers/usb/dwc3/core.c. core.c
is the one which handled Global Address space, gadget.c handled Device
Address space and host.c passed xHCI Address space to xhci-hcd.ko

> +static inline bool dwc3_hiber_enabled(struct dwc3 *dwc)
> +{
> +	return DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1) ==
> +		DWC3_GHWPARAMS1_EN_PWROPT_HIB;
> +}
> +
> +static inline bool dwc3_in_hibernation(struct dwc3 *dwc)
> +{
> +	return dwc->hibernate >= DWC3_HIBER_SLEEPING &&
> +		dwc->hibernate != DWC3_HIBER_SS_DIS_QUIRK;
> +}
> +
> +static inline void dwc3_enter_hiber_nosave(struct dwc3 *dwc)
> +{
> +	if (dwc3_hiber_enabled(dwc))
> +		dwc->hibernate = DWC3_HIBER_ENTER_NOSAVE;
> +}
> +
> +static inline void dwc3_enter_hiber_save(struct dwc3 *dwc)
> +{
> +	if (dwc3_hiber_enabled(dwc))
> +		dwc->hibernate = DWC3_HIBER_ENTER_SAVE;
> +}
> +
> +static inline void dwc3_gadget_get_ctlr(struct dwc3 *dwc)
> +{
> +	dwc->usage_cnt++;
> +}
> +
> +static inline void dwc3_gadget_put_ctlr(struct dwc3 *dwc)
> +{
> +	dwc->usage_cnt--;
> +}

why do you need this ? You can use pm_runtime_get()/pm_runtime_put()

> +#define dwc3_wait_if_hibernating(_dwc, _flags)				\
> +{									\
> +	int _temp = (_dwc)->hibernate;					\
> +	while (_temp >= DWC3_HIBER_SLEEPING &&				\
> +			_temp != DWC3_HIBER_SS_DIS_QUIRK) {		\
> +		spin_unlock_irqrestore(&(_dwc)->lock, (_flags));	\
> +		msleep(1);						\
> +		spin_lock_irqsave(&(_dwc)->lock, (_flags));		\
> +		_temp = (_dwc)->hibernate;				\
> +	}								\
> +}

if HW go boo-boo, this could become quite dangerous and freeze the whole
machine. Whenever you add a wait/sleep, you need to have a way out of a
possible infinite loop.

-- 
balbi

Attachment: signature.asc
Description: Digital 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