Re: [PATCH 6/7 v2] usb: dwc3: refactor some existing routines for hibernation support

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

 



On Wed, Feb 15, 2012 at 06:57:01PM -0800, Paul Zimmerman wrote:
> Some existing routines need to be refactored for hibernation. This
> includes event buffer setup, restoring saved state when an EP is
> configured, stopping a transfer without the FORCERM bit set, and
> stopping a transfer on EP0-OUT.
> 
> In addition, some routines need to be made non-static, so that the
> hibernation code, which will live in a separate source file, can
> call them. In particular, this requires splitting dwc3_gadget_start
> into two functions, a driver-private one that just starts the
> hardware, and full-function one that is called through the gadget
> API.
> 
> Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx>
> ---
>  drivers/usb/dwc3/core.c   |    5 ++-
>  drivers/usb/dwc3/core.h   |    4 ++
>  drivers/usb/dwc3/gadget.c |  116 ++++++++++++++++++++++++++------------------
>  drivers/usb/dwc3/gadget.h |    8 +++
>  4 files changed, 84 insertions(+), 49 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 7124ec0..829c0d2 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -256,7 +256,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 +266,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;

Why ? the events are zero-initialized anyway.

>  		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
>  				lower_32_bits(evt->dma));
> @@ -286,6 +287,8 @@ 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;

why ? this will only be called right before freeing the event buffer
memory.

> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 87dab09..b300c30 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -395,6 +395,7 @@ struct dwc3_event_buffer {
>   * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
>   * @res_trans_idx: Resource transfer index
>   * @interval: the intervall on which the ISOC transfer is started
> + * @saved_state: ep state saved during hibernation
>   * @name: a human readable name e.g. ep1out-bulk
>   * @direction: true for TX, false for RX
>   * @stream_capable: true when streams are enabled
> @@ -428,6 +429,7 @@ struct dwc3_ep {
>  	u8			type;
>  	u8			res_trans_idx;
>  	u32			interval;
> +	u32			saved_state;
>  
>  	char			name[20];
>  
> @@ -838,6 +840,8 @@ void dwc3_host_exit(struct dwc3 *dwc);
>  int dwc3_gadget_init(struct dwc3 *dwc);
>  void dwc3_gadget_exit(struct dwc3 *dwc);
>  
> +int dwc3_event_buffers_setup(struct dwc3 *dwc);
> +
>  extern int dwc3_get_device_id(void);
>  extern void dwc3_put_device_id(int id);
>  
> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index fdaef9a..93eb673 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
> @@ -495,7 +495,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;
>  
> @@ -537,6 +538,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);
>  }
> @@ -560,9 +566,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;
> @@ -574,7 +581,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;
>  
> @@ -614,13 +621,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);
> @@ -720,7 +726,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;
> @@ -1161,7 +1167,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",
> @@ -1396,7 +1402,7 @@ 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)
>  {
>  	u32			reg;
>  	u32			timeout = 500;
> @@ -1451,47 +1457,24 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
>  	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)

I still don't see the need to expose this to another source file. Just
call this from your runtime_resume method, maybe that's what you're
doing but runtime_resume was defined on core.c... I will soo figure it
out, but even in that case, I believe exposing gadget_stat is the wrong
way to handle things, maybe you need to expose a new API:

dwc3_gadget_runtime_suspend()
dwc3_gadget_runtime_resume()

and call those from core.c's runtime_suspend/runtime_resume
respectively if core is configured as DRD or Device modes. Similarly, we
will need a set of hooks for host, I guess.

>  {
> -	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;
> @@ -1501,14 +1484,47 @@ 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);
> +
> +	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:
>  	spin_unlock_irqrestore(&dwc->lock, flags);
>  
>  	return ret;
> @@ -1882,7 +1898,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;
> @@ -1891,10 +1907,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;
> +		cmd |= DWC3_DEPCMD_CMDIOC;
>  		cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
>  		memset(&params, 0, sizeof(params));
>  		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
> @@ -2097,7 +2117,7 @@ static void dwc3_gadget_suspend_phy(struct dwc3 *dwc, u8 speed)
>  	}
>  }
>  
> -static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
> +void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
>  {
>  	struct dwc3_gadget_ep_cmd_params params;
>  	struct dwc3_ep		*dep;
> @@ -2162,14 +2182,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
>  	}
>  
>  	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, false);
>  	if (ret) {
>  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
>  		return;
>  	}
>  
>  	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, false);
>  	if (ret) {
>  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
>  		return;
> diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
> index d668cb1..a962d53 100644
> --- a/drivers/usb/dwc3/gadget.h
> +++ b/drivers/usb/dwc3/gadget.h
> @@ -114,10 +114,18 @@ 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_gadget_run_stop(struct dwc3 *dwc, int is_on);

This is also something I think doesn't need to be exposed. You should
save what's on DCTL instead, no ? That way, if we hibernated without
being connected to anything, we don't try to set run_stop bit when we
resume.

-- 
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