Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8b9c974 authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by Felipe Balbi
Browse files

usb: renesas_usbhs: gadget: disable all eps when the driver stops



A gadget driver will not disable eps immediately when ->disconnect()
is called. But, since this driver assumes all eps stop after
the ->disconnect(), unexpected behavior happens (especially in system
suspend).
So, this patch disables all eps in usbhsg_try_stop(). After disabling
eps by renesas_usbhs driver, since some functions will be called by
both a gadget and renesas_usbhs driver, renesas_usbhs driver should
protect uep->pipe. To protect uep->pipe easily, this patch adds a new
lock in struct usbhsg_uep.

Fixes: 2f98382d ("usb: renesas_usbhs: Add Renesas USBHS Gadget")
Cc: <stable@vger.kernel.org> # v3.0+
Signed-off-by: default avatarYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 59a0879a
Loading
Loading
Loading
Loading
+24 −7
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ struct usbhsg_gpriv;
struct usbhsg_uep {
	struct usb_ep		 ep;
	struct usbhs_pipe	*pipe;
	spinlock_t		lock;	/* protect the pipe */

	char ep_name[EP_NAME_SIZE];

@@ -636,10 +637,16 @@ static int usbhsg_ep_enable(struct usb_ep *ep,
static int usbhsg_ep_disable(struct usb_ep *ep)
{
	struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
	struct usbhs_pipe *pipe;
	unsigned long flags;
	int ret = 0;

	if (!pipe)
		return -EINVAL;
	spin_lock_irqsave(&uep->lock, flags);
	pipe = usbhsg_uep_to_pipe(uep);
	if (!pipe) {
		ret = -EINVAL;
		goto out;
	}

	usbhsg_pipe_disable(uep);
	usbhs_pipe_free(pipe);
@@ -647,6 +654,9 @@ static int usbhsg_ep_disable(struct usb_ep *ep)
	uep->pipe->mod_private	= NULL;
	uep->pipe		= NULL;

out:
	spin_unlock_irqrestore(&uep->lock, flags);

	return 0;
}

@@ -696,8 +706,11 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
	struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
	struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
	struct usbhs_pipe *pipe;
	unsigned long flags;

	spin_lock_irqsave(&uep->lock, flags);
	pipe = usbhsg_uep_to_pipe(uep);
	if (pipe)
		usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));

@@ -706,6 +719,7 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
	 * even if the pipe is NULL.
	 */
	usbhsg_queue_pop(uep, ureq, -ECONNRESET);
	spin_unlock_irqrestore(&uep->lock, flags);

	return 0;
}
@@ -852,10 +866,10 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
{
	struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
	struct usbhs_mod *mod = usbhs_mod_get_current(priv);
	struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv);
	struct usbhsg_uep *uep;
	struct device *dev = usbhs_priv_to_dev(priv);
	unsigned long flags;
	int ret = 0;
	int ret = 0, i;

	/********************  spin lock ********************/
	usbhs_lock(priv, flags);
@@ -887,7 +901,9 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
	usbhs_sys_set_test_mode(priv, 0);
	usbhs_sys_function_ctrl(priv, 0);

	usbhsg_ep_disable(&dcp->ep);
	/* disable all eps */
	usbhsg_for_each_uep_with_dcp(uep, gpriv, i)
		usbhsg_ep_disable(&uep->ep);

	dev_dbg(dev, "stop gadget\n");

@@ -1069,6 +1085,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
		ret = -ENOMEM;
		goto usbhs_mod_gadget_probe_err_gpriv;
	}
	spin_lock_init(&uep->lock);

	gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
	dev_info(dev, "%stransceiver found\n",