Commit a95bdfd2 authored by Sasi Kumar's avatar Sasi Kumar Committed by Felipe Balbi

bdc: Fix bug causing crash after multiple disconnects

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: default avatarSasi Kumar <sasi.kumar@broadcom.com>
Signed-off-by: default avatarAl Cooper <alcooperx@gmail.com>
Acked-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarFelipe Balbi <balbi@kernel.org>
parent 4e3a765b
...@@ -278,6 +278,7 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit) ...@@ -278,6 +278,7 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit)
* in that case reinit is passed as 1 * in that case reinit is passed as 1
*/ */
if (reinit) { if (reinit) {
int i;
/* Enable interrupts */ /* Enable interrupts */
temp = bdc_readl(bdc->regs, BDC_BDCSC); temp = bdc_readl(bdc->regs, BDC_BDCSC);
temp |= BDC_GIE; temp |= BDC_GIE;
...@@ -287,6 +288,9 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit) ...@@ -287,6 +288,9 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit)
/* Initialize SRR to 0 */ /* Initialize SRR to 0 */
memset(bdc->srr.sr_bds, 0, memset(bdc->srr.sr_bds, 0,
NUM_SR_ENTRIES * sizeof(struct bdc_bd)); 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 { } else {
/* One time initiaization only */ /* One time initiaization only */
/* Enable status report function pointers */ /* Enable status report function pointers */
......
...@@ -615,7 +615,6 @@ int bdc_ep_enable(struct bdc_ep *ep) ...@@ -615,7 +615,6 @@ int bdc_ep_enable(struct bdc_ep *ep)
} }
bdc_dbg_bd_list(bdc, ep); bdc_dbg_bd_list(bdc, ep);
/* only for ep0: config ep is called for ep0 from connect event */ /* only for ep0: config ep is called for ep0 from connect event */
ep->flags |= BDC_EP_ENABLED;
if (ep->ep_num == 1) if (ep->ep_num == 1)
return ret; return ret;
...@@ -759,10 +758,13 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) ...@@ -759,10 +758,13 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
__func__, ep->name, start_bdi, end_bdi); __func__, ep->name, start_bdi, end_bdi);
dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n", dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n",
ep, (void *)ep->usb_ep.desc); ep, (void *)ep->usb_ep.desc);
/* Stop the ep to see where the HW is ? */ /* if still connected, stop the ep to see where the HW is ? */
ret = bdc_stop_ep(bdc, ep->ep_num); if (!(bdc_readl(bdc->regs, BDC_USPC) & BDC_PST_MASK)) {
/* if there is an issue with stopping ep, then no need to go further */ ret = bdc_stop_ep(bdc, ep->ep_num);
if (ret) /* if there is an issue, then no need to go further */
if (ret)
return 0;
} else
return 0; return 0;
/* /*
...@@ -1911,7 +1913,9 @@ static int bdc_gadget_ep_disable(struct usb_ep *_ep) ...@@ -1911,7 +1913,9 @@ static int bdc_gadget_ep_disable(struct usb_ep *_ep)
__func__, ep->name, ep->flags); __func__, ep->name, ep->flags);
if (!(ep->flags & BDC_EP_ENABLED)) { 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; return 0;
} }
spin_lock_irqsave(&bdc->lock, flags); spin_lock_irqsave(&bdc->lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment