aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorNeil Zhang <zhangwm@marvell.com>2011-10-12 04:49:31 -0400
committerFelipe Balbi <balbi@ti.com>2011-10-13 13:42:03 -0400
commit27cec2b2f7a4d2394af63a3dc7928975f4c072f4 (patch)
tree32b1c478bb32af364493528ab93d7de4a9b3398d /drivers/usb
parent96c2bbb09d0742148a305d7afbdf7c5803fd78c1 (diff)
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>
Diffstat (limited to 'drivers/usb')
-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,
497 u16 max = 0; 497 u16 max = 0;
498 u32 bit_pos, epctrlx, direction; 498 u32 bit_pos, epctrlx, direction;
499 unsigned char zlt = 0, ios = 0, mult = 0; 499 unsigned char zlt = 0, ios = 0, mult = 0;
500 unsigned long flags;
500 501
501 ep = container_of(_ep, struct mv_ep, ep); 502 ep = container_of(_ep, struct mv_ep, ep);
502 udc = ep->udc; 503 udc = ep->udc;
@@ -517,9 +518,6 @@ static int mv_ep_enable(struct usb_ep *_ep,
517 */ 518 */
518 zlt = 1; 519 zlt = 1;
519 520
520 /* Get the endpoint queue head address */
521 dqh = (struct mv_dqh *)ep->dqh;
522
523 bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); 521 bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
524 522
525 /* Check if the Endpoint is Primed */ 523 /* Check if the Endpoint is Primed */
@@ -556,6 +554,10 @@ static int mv_ep_enable(struct usb_ep *_ep,
556 default: 554 default:
557 goto en_done; 555 goto en_done;
558 } 556 }
557
558 spin_lock_irqsave(&udc->lock, flags);
559 /* Get the endpoint queue head address */
560 dqh = ep->dqh;
559 dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) 561 dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS)
560 | (mult << EP_QUEUE_HEAD_MULT_POS) 562 | (mult << EP_QUEUE_HEAD_MULT_POS)
561 | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0) 563 | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0)
@@ -600,6 +602,8 @@ static int mv_ep_enable(struct usb_ep *_ep,
600 writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); 602 writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]);
601 } 603 }
602 604
605 spin_unlock_irqrestore(&udc->lock, flags);
606
603 return 0; 607 return 0;
604en_done: 608en_done:
605 return -EINVAL; 609 return -EINVAL;
@@ -611,6 +615,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
611 struct mv_ep *ep; 615 struct mv_ep *ep;
612 struct mv_dqh *dqh; 616 struct mv_dqh *dqh;
613 u32 bit_pos, epctrlx, direction; 617 u32 bit_pos, epctrlx, direction;
618 unsigned long flags;
614 619
615 ep = container_of(_ep, struct mv_ep, ep); 620 ep = container_of(_ep, struct mv_ep, ep);
616 if ((_ep == NULL) || !ep->desc) 621 if ((_ep == NULL) || !ep->desc)
@@ -621,6 +626,8 @@ static int mv_ep_disable(struct usb_ep *_ep)
621 /* Get the endpoint queue head address */ 626 /* Get the endpoint queue head address */
622 dqh = ep->dqh; 627 dqh = ep->dqh;
623 628
629 spin_lock_irqsave(&udc->lock, flags);
630
624 direction = ep_dir(ep); 631 direction = ep_dir(ep);
625 bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); 632 bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
626 633
@@ -639,6 +646,9 @@ static int mv_ep_disable(struct usb_ep *_ep)
639 646
640 ep->desc = NULL; 647 ep->desc = NULL;
641 ep->stopped = 1; 648 ep->stopped = 1;
649
650 spin_unlock_irqrestore(&udc->lock, flags);
651
642 return 0; 652 return 0;
643} 653}
644 654