Skip to content

Commit

Permalink
usb: gadget: mv_udc: add missing spinlock in ep enable/disable
Browse files Browse the repository at this point in the history
The ep enable / disable functions can be called from interrupt
context, and they are not race safe on SMP systems. The critical
data can be modified in more than one routing.
Make them race safe by using IRQ-safe spinlock functions.

Signed-off-by: Neil Zhang <zhangwm@marvell.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
  • Loading branch information
Neil Zhang authored and Felipe Balbi committed Oct 13, 2011
1 parent 96c2bbb commit 27cec2b
Showing 1 changed file with 13 additions and 3 deletions.
16 changes: 13 additions & 3 deletions drivers/usb/gadget/mv_udc_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
u16 max = 0;
u32 bit_pos, epctrlx, direction;
unsigned char zlt = 0, ios = 0, mult = 0;
unsigned long flags;

ep = container_of(_ep, struct mv_ep, ep);
udc = ep->udc;
Expand All @@ -517,9 +518,6 @@ static int mv_ep_enable(struct usb_ep *_ep,
*/
zlt = 1;

/* Get the endpoint queue head address */
dqh = (struct mv_dqh *)ep->dqh;

bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);

/* Check if the Endpoint is Primed */
Expand Down Expand Up @@ -556,6 +554,10 @@ static int mv_ep_enable(struct usb_ep *_ep,
default:
goto en_done;
}

spin_lock_irqsave(&udc->lock, flags);
/* Get the endpoint queue head address */
dqh = ep->dqh;
dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
| (mult << EP_QUEUE_HEAD_MULT_POS)
| (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0)
Expand Down Expand Up @@ -600,6 +602,8 @@ static int mv_ep_enable(struct usb_ep *_ep,
writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
}

spin_unlock_irqrestore(&udc->lock, flags);

return 0;
en_done:
return -EINVAL;
Expand All @@ -611,6 +615,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
struct mv_ep *ep;
struct mv_dqh *dqh;
u32 bit_pos, epctrlx, direction;
unsigned long flags;

ep = container_of(_ep, struct mv_ep, ep);
if ((_ep == NULL) || !ep->desc)
Expand All @@ -621,6 +626,8 @@ static int mv_ep_disable(struct usb_ep *_ep)
/* Get the endpoint queue head address */
dqh = ep->dqh;

spin_lock_irqsave(&udc->lock, flags);

direction = ep_dir(ep);
bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);

Expand All @@ -639,6 +646,9 @@ static int mv_ep_disable(struct usb_ep *_ep)

ep->desc = NULL;
ep->stopped = 1;

spin_unlock_irqrestore(&udc->lock, flags);

return 0;
}

Expand Down

0 comments on commit 27cec2b

Please sign in to comment.