lkml.org 
[lkml]   [2017]   [Jul]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.12 073/196] usb: renesas_usbhs: gadget: disable all eps when the driver stops
    Date
    4.12-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>

    commit b8b9c974afee685789fcbb191b52d1790be3608c upstream.

    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: 2f98382dc ("usb: renesas_usbhs: Add Renesas USBHS Gadget")
    Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
    Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/renesas_usbhs/mod_gadget.c | 31 ++++++++++++++++++++++++-------
    1 file changed, 24 insertions(+), 7 deletions(-)

    --- a/drivers/usb/renesas_usbhs/mod_gadget.c
    +++ b/drivers/usb/renesas_usbhs/mod_gadget.c
    @@ -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 @@ usbhsg_ep_enable_end:
    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_
    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_
    {
    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_
    * 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_
    {
    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_
    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_
    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",

    \
     
     \ /
      Last update: 2017-07-25 21:25    [W:6.544 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site