lkml.org 
[lkml]   [2020]   [Aug]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 076/228] bdc: Fix bug causing crash after multiple disconnects
    Date
    From: Sasi Kumar <sasi.kumar@broadcom.com>

    [ Upstream commit a95bdfd22076497288868c028619bc5995f5cc7f ]

    Multiple connects/disconnects can cause a crash on the second
    disconnect. The driver had a problem where it would try to send
    endpoint commands after it was disconnected which is not allowed
    by the hardware. The fix is to only allow the endpoint commands
    when the endpoint is connected. This will also fix issues that
    showed up when using configfs to create gadgets.

    Signed-off-by: Sasi Kumar <sasi.kumar@broadcom.com>
    Signed-off-by: Al Cooper <alcooperx@gmail.com>
    Acked-by: Florian Fainelli <f.fainelli@gmail.com>
    Signed-off-by: Felipe Balbi <balbi@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/usb/gadget/udc/bdc/bdc_core.c | 4 ++++
    drivers/usb/gadget/udc/bdc/bdc_ep.c | 16 ++++++++++------
    2 files changed, 14 insertions(+), 6 deletions(-)

    diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
    index 7a8af4b916cff..2660cc2e42a08 100644
    --- a/drivers/usb/gadget/udc/bdc/bdc_core.c
    +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
    @@ -288,6 +288,7 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit)
    * in that case reinit is passed as 1
    */
    if (reinit) {
    + int i;
    /* Enable interrupts */
    temp = bdc_readl(bdc->regs, BDC_BDCSC);
    temp |= BDC_GIE;
    @@ -297,6 +298,9 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit)
    /* Initialize SRR to 0 */
    memset(bdc->srr.sr_bds, 0,
    NUM_SR_ENTRIES * sizeof(struct bdc_bd));
    + /* clear ep flags to avoid post disconnect stops/deconfigs */
    + for (i = 1; i < bdc->num_eps; ++i)
    + bdc->bdc_ep_array[i]->flags = 0;
    } else {
    /* One time initiaization only */
    /* Enable status report function pointers */
    diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c
    index be9f40bc9c12b..bb2d5ebd97b52 100644
    --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c
    +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c
    @@ -621,7 +621,6 @@ int bdc_ep_enable(struct bdc_ep *ep)
    }
    bdc_dbg_bd_list(bdc, ep);
    /* only for ep0: config ep is called for ep0 from connect event */
    - ep->flags |= BDC_EP_ENABLED;
    if (ep->ep_num == 1)
    return ret;

    @@ -765,10 +764,13 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
    __func__, ep->name, start_bdi, end_bdi);
    dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n",
    ep, (void *)ep->usb_ep.desc);
    - /* Stop the ep to see where the HW is ? */
    - ret = bdc_stop_ep(bdc, ep->ep_num);
    - /* if there is an issue with stopping ep, then no need to go further */
    - if (ret)
    + /* if still connected, stop the ep to see where the HW is ? */
    + if (!(bdc_readl(bdc->regs, BDC_USPC) & BDC_PST_MASK)) {
    + ret = bdc_stop_ep(bdc, ep->ep_num);
    + /* if there is an issue, then no need to go further */
    + if (ret)
    + return 0;
    + } else
    return 0;

    /*
    @@ -1917,7 +1919,9 @@ static int bdc_gadget_ep_disable(struct usb_ep *_ep)
    __func__, ep->name, ep->flags);

    if (!(ep->flags & BDC_EP_ENABLED)) {
    - dev_warn(bdc->dev, "%s is already disabled\n", ep->name);
    + if (bdc->gadget.speed != USB_SPEED_UNKNOWN)
    + dev_warn(bdc->dev, "%s is already disabled\n",
    + ep->name);
    return 0;
    }
    spin_lock_irqsave(&bdc->lock, flags);
    --
    2.25.1


    \
     
     \ /
      Last update: 2020-08-20 13:13    [W:3.124 / U:22.336 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site