]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
usb: musb: Reselect index reg in interrupt context
authorSupriya Karanth <supriya.karanth@stericsson.com>
Fri, 17 Feb 2012 09:24:52 +0000 (14:54 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 2 Apr 2012 16:52:29 +0000 (09:52 -0700)
commit 39287076e46d2c19aaceaa6f0a44168ae4d257ec upstream.

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

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>
drivers/usb/musb/musb_gadget.c

index 922148ff8d2969de64a808046f7ce06c6115ace1..c860597eeb3aa9a9bd4be2680fedb50d7bac032d 100644 (file)
@@ -576,6 +576,15 @@ void musb_g_tx(struct musb *musb, u8 epnum)
 
                if (request->actual == request->length) {
                        musb_g_giveback(musb_ep, request, 0);
+                       /*
+                        * In the giveback function the MUSB lock is
+                        * released and acquired after sometime. During
+                        * this time period the INDEX register could get
+                        * changed by the gadget_queue function especially
+                        * on SMP systems. Reselect the INDEX to be sure
+                        * we are reading/modifying the right registers
+                        */
+                       musb_ep_select(mbase, epnum);
                        req = musb_ep->desc ? next_request(musb_ep) : NULL;
                        if (!req) {
                                dev_dbg(musb->controller, "%s idle now\n",
@@ -985,6 +994,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
                }
 #endif
                musb_g_giveback(musb_ep, request, 0);
+               /*
+                * In the giveback function the MUSB lock is
+                * released and acquired after sometime. During
+                * this time period the INDEX register could get
+                * changed by the gadget_queue function especially
+                * on SMP systems. Reselect the INDEX to be sure
+                * we are reading/modifying the right registers
+                */
+               musb_ep_select(mbase, epnum);
 
                req = next_request(musb_ep);
                if (!req)