Commit 27cec2b2 authored by Neil Zhang's avatar Neil Zhang Committed by Felipe Balbi

usb: gadget: mv_udc: add missing spinlock in ep enable/disable

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: default avatarNeil Zhang <zhangwm@marvell.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 96c2bbb0
...@@ -497,6 +497,7 @@ static int mv_ep_enable(struct usb_ep *_ep, ...@@ -497,6 +497,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
u16 max = 0; u16 max = 0;
u32 bit_pos, epctrlx, direction; u32 bit_pos, epctrlx, direction;
unsigned char zlt = 0, ios = 0, mult = 0; unsigned char zlt = 0, ios = 0, mult = 0;
unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep); ep = container_of(_ep, struct mv_ep, ep);
udc = ep->udc; udc = ep->udc;
...@@ -517,9 +518,6 @@ static int mv_ep_enable(struct usb_ep *_ep, ...@@ -517,9 +518,6 @@ static int mv_ep_enable(struct usb_ep *_ep,
*/ */
zlt = 1; 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); bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
/* Check if the Endpoint is Primed */ /* Check if the Endpoint is Primed */
...@@ -556,6 +554,10 @@ static int mv_ep_enable(struct usb_ep *_ep, ...@@ -556,6 +554,10 @@ static int mv_ep_enable(struct usb_ep *_ep,
default: default:
goto en_done; 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) dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
| (mult << EP_QUEUE_HEAD_MULT_POS) | (mult << EP_QUEUE_HEAD_MULT_POS)
| (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0) | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0)
...@@ -600,6 +602,8 @@ static int mv_ep_enable(struct usb_ep *_ep, ...@@ -600,6 +602,8 @@ static int mv_ep_enable(struct usb_ep *_ep,
writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
} }
spin_unlock_irqrestore(&udc->lock, flags);
return 0; return 0;
en_done: en_done:
return -EINVAL; return -EINVAL;
...@@ -611,6 +615,7 @@ static int mv_ep_disable(struct usb_ep *_ep) ...@@ -611,6 +615,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
struct mv_ep *ep; struct mv_ep *ep;
struct mv_dqh *dqh; struct mv_dqh *dqh;
u32 bit_pos, epctrlx, direction; u32 bit_pos, epctrlx, direction;
unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep); ep = container_of(_ep, struct mv_ep, ep);
if ((_ep == NULL) || !ep->desc) if ((_ep == NULL) || !ep->desc)
...@@ -621,6 +626,8 @@ static int mv_ep_disable(struct usb_ep *_ep) ...@@ -621,6 +626,8 @@ static int mv_ep_disable(struct usb_ep *_ep)
/* Get the endpoint queue head address */ /* Get the endpoint queue head address */
dqh = ep->dqh; dqh = ep->dqh;
spin_lock_irqsave(&udc->lock, flags);
direction = ep_dir(ep); direction = ep_dir(ep);
bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
...@@ -639,6 +646,9 @@ static int mv_ep_disable(struct usb_ep *_ep) ...@@ -639,6 +646,9 @@ static int mv_ep_disable(struct usb_ep *_ep)
ep->desc = NULL; ep->desc = NULL;
ep->stopped = 1; ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
return 0; return 0;
} }
......
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