summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Zhang <zhangwm@marvell.com>2011-10-12 10:49:31 +0200
committerFelipe Balbi <balbi@ti.com>2011-10-13 19:42:03 +0200
commit27cec2b2f7a4d2394af63a3dc7928975f4c072f4 (patch)
tree32b1c478bb32af364493528ab93d7de4a9b3398d
parentusb: gadget: mv_udc: fix bug when handle setup package. (diff)
downloadlinux-27cec2b2f7a4d2394af63a3dc7928975f4c072f4.tar.xz
linux-27cec2b2f7a4d2394af63a3dc7928975f4c072f4.zip
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: Neil Zhang <zhangwm@marvell.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/mv_udc_core.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index fcb980def624..501b05a253cc 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -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;
@@ -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 */
@@ -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)
@@ -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;
@@ -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)
@@ -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);
@@ -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;
}