aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb
diff options
context:
space:
mode:
authorSupriya Karanth <supriya.karanth@stericsson.com>2012-02-17 04:24:52 -0500
committerFelipe Balbi <balbi@ti.com>2012-02-24 05:23:02 -0500
commit39287076e46d2c19aaceaa6f0a44168ae4d257ec (patch)
treeeb7dfa3d684aa445a03960ced3af5d723528be8c /drivers/usb/musb
parent6c2abcdd4f8e21ce686a26697de0ce198a16eaed (diff)
usb: musb: Reselect index reg in interrupt context
musb INDEX register is getting modified/corrupted during temporary un-locking in a SMP system. Set this register with proper value after re-acquiring the lock Scenario: --------- CPU1 is handling a data transfer completion interrupt received for the CLASS1 EP CPU2 is handling a CLASS2 thread which is queuing data to musb for transfer Below is the error sequence: CPU1 | CPU2 -------------------------------------------------------------------- Data transfer completion inter- | rupt recieved. | | musb INDEX reg set to CLASS1 EP | | musb LOCK is acquired. | | | CLASS2 thread queues data. | | CLASS2 thread tries to acquire musb | LOCK but lock is already taken by | CLASS1, so CLASS2 thread is | spinning. | From Interrupt Context musb | giveback function is called | | The giveback function releases | CLASS2 thread now acquires LOCK LOCK | | ClASS1 Request's completion cal-| ClASS2 schedules the data transfer and lback is called | sets the MUSB INDEX to Class2 EP number | Interrupt handler for CLASS1 EP | tries to acquire LOCK and is | spinning | | Interrupt for Class1 EP acquires| Class2 completes the scheduling etc and the MUSB LOCK | releases the musb LOCK | Interrupt for Class1 EP schedul-| es the next data transfer | but musb INDEX register is still| set to CLASS2 EP | Since the MUSB INDEX register is set to a different endpoint, we read and modify the wrong registers. Hence data transfer will not happen properly. This results in unpredictable behavior So, the MUSB INDEX register is set to proper value again when interrupt re-acquires the lock Cc: stable@vger.kernel.org Signed-off-by: Supriya Karanth <supriya.karanth@stericsson.com> Signed-off-by: Praveena Nadahally <praveen.nadahally@stericsson.com> Reviewed-by: srinidhi kasagar <srinidhi.kasagar@stericsson.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/musb_gadget.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 59ab98f08e9e..957d9ca3d06d 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -574,6 +574,15 @@ void musb_g_tx(struct musb *musb, u8 epnum)
574 574
575 if (request->actual == request->length) { 575 if (request->actual == request->length) {
576 musb_g_giveback(musb_ep, request, 0); 576 musb_g_giveback(musb_ep, request, 0);
577 /*
578 * In the giveback function the MUSB lock is
579 * released and acquired after sometime. During
580 * this time period the INDEX register could get
581 * changed by the gadget_queue function especially
582 * on SMP systems. Reselect the INDEX to be sure
583 * we are reading/modifying the right registers
584 */
585 musb_ep_select(mbase, epnum);
577 req = musb_ep->desc ? next_request(musb_ep) : NULL; 586 req = musb_ep->desc ? next_request(musb_ep) : NULL;
578 if (!req) { 587 if (!req) {
579 dev_dbg(musb->controller, "%s idle now\n", 588 dev_dbg(musb->controller, "%s idle now\n",
@@ -983,6 +992,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
983 } 992 }
984#endif 993#endif
985 musb_g_giveback(musb_ep, request, 0); 994 musb_g_giveback(musb_ep, request, 0);
995 /*
996 * In the giveback function the MUSB lock is
997 * released and acquired after sometime. During
998 * this time period the INDEX register could get
999 * changed by the gadget_queue function especially
1000 * on SMP systems. Reselect the INDEX to be sure
1001 * we are reading/modifying the right registers
1002 */
1003 musb_ep_select(mbase, epnum);
986 1004
987 req = next_request(musb_ep); 1005 req = next_request(musb_ep);
988 if (!req) 1006 if (!req)