[RFC] USB: GADGET: Fix queue synchronization issue in tx

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On SMP systems there is a synchronization issue in the gadget
serial driver which potentially causes a packet swap on some
occasions. In the gadget serial driver implementation, a transfer
is queued to the controller on the following two occasions.

1. Application requesting to send data through gadget serial driver:
2. Previously scheduled transfer is complete and a new transfer is
   triggered from the callback function:

On SMP systems, sometimes there is a packet swap since the port lock
is being dropped briefly during queueing. On some occasions, as both
the completion routine and the application are trying to queue the data
at the same time, due to the lock being dropped, the packets gets
swapped before they get queued to the endpoint.

               CPU1                             CPU2
----------------------------------+----------------------------------
                                  | u_serial submits request1
                                  | to controller
                                  |
                                  | controller processes request1
                                  | and sends it over the bus
                                  |
 Interrupt received for request1  |
 completion. Completion forwarded |
 to u_serial.                     |
                                  |
                                  |
 gs_write_complete is invoked     |
 for request1 completion from     |
 interrupt context                |
                                  |
 PORT LOCK ACQUIRED               |
 u_serial tries to queue request  |
 from the completion context by   |
 calling gs_start_tx. request2    |
 is fetched from the list.        |
                                  | u_serial is ready to submit
                                  | next request from the
                                  | application context
                                  | WAITING FOR LOCK
                                  |
 gs_start_tx releases port lock   |
 before request is queued to      |
 the endpoint.                    |
PORT LOCK RELEASED                |
                                  |
                                  | Application context sneaks in
                                  | and acquires lock in gs_write
                                  | PORT LOCK ACQUIRED
                                  |   Fetches request3 from the list
                                  | PORT LOCK RELEASED
                                  |   Queues request3 to endpoint
                                  | PORT LOCK ACQUIRED
                                  |   Completes the request queueing
                                  | request3 is queued ahead of request2
                                  | PORT LOCK RELEASED
                                  |
 request2 is queued to the        |
 endpoint from the interrupt      |
 context after request3 is queued.|
PORT LOCK ACQUIRED BACK           |

Signed-off-by: Balakumar Rajendran <balakumar.rajendran@xxxxxxxxxxxxxx>
Signed-off-by: Praveena Nadahally <praveen.nadahally@xxxxxxxxxxxxxx>
Acked-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
---
 drivers/usb/gadget/u_serial.c |   15 ++++++++-------
 1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 5b3f5ff..0bcc8cd 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -384,16 +384,17 @@ __acquires(&port->port_lock)
 				port->port_num, len, *((u8 *)req->buf),
 				*((u8 *)req->buf+1), *((u8 *)req->buf+2));
 
-		/* Drop lock while we call out of driver; completions
-		 * could be issued while we do so.  Disconnection may
-		 * happen too; maybe immediately before we queue this!
+		/*
+		 * Do not drop lock here. It causes packet swaps in
+		 * SMP systems when both the interrupt context and the
+		 * application context and trying to queue data. Packets
+		 * get queued in wrong order sometimes.
 		 *
-		 * NOTE that we may keep sending data for a while after
-		 * the TTY closed (dev->ioport->port_tty is NULL).
+		 * TODO: For musb no issue is observed during the
+		 * disconnect sequence as well. Needs to be verified
+		 * with other controllers.
 		 */
-		spin_unlock(&port->port_lock);
 		status = usb_ep_queue(in, req, GFP_ATOMIC);
-		spin_lock(&port->port_lock);
 
 		if (status) {
 			pr_debug("%s: %s %s err %d\n",
-- 
1.7.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux