• Philip Oberstaller's avatar
    usb: gadget: serial: fix re-ordering of tx data · 3e9d3d2e
    Philip Oberstaller authored
    When a single thread is sending out data over the gadget serial port,
    gs_start_tx() will be called both from the sender context and from the
    write completion. Since the port lock is released before the packet is
    queued, the order in which the URBs are submitted is not guaranteed.
    E.g.
    
      sending thread                      completion (interrupt)
    
      gs_write()
        LOCK
                                          gs_write_complete()
                                            LOCK (wait)
        gs_start_tx()
          req1 = list_entry(pool->next)
          UNLOCK
                                            LOCK (acquired)
                                            gs_start_tx()
                                              req2 = list_entry(pool->next)
                                              UNLOCK
                                              usb_ep_queue(req2)
          usb_ep_queue(req1)
    
    I.e., req2 is submitted before req1 but it contains the data that
    comes after req1.
    
    To reproduce, use SMP with sending thread and completion pinned to
    different CPUs, or use PREEMPT_RT, and add the following delay just
    before the call to usb_ep_queue():
    
    		if (port->write_started > 0 && !list_empty(pool))
    			udelay(1000);
    
    To work around this problem, make sure that only one thread is running
    through the gs_start_tx() loop with an extra flag write_busy. Since
    gs_start_tx() is always called with the port lock held, no further
    synchronisation is needed. The original caller will continue through
    the loop when the request was successfully submitted.
    Signed-off-by: default avatarPhilip Oberstaller <Philip.Oberstaller@septentrio.com>
    Signed-off-by: default avatarArnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
    Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
    3e9d3d2e
u_serial.c 33.3 KB