• Felipe Balbi's avatar
    usb: dwc3: gadget: never call ->complete() from ->ep_queue() · c91815b5
    Felipe Balbi authored
    This is a requirement which has always existed but, somehow, wasn't
    reflected in the documentation and problems weren't found until now
    when Tuba Yavuz found a possible deadlock happening between dwc3 and
    f_hid. She described the situation as follows:
    
    spin_lock_irqsave(&hidg->write_spinlock, flags); // first acquire
    /* we our function has been disabled by host */
    if (!hidg->req) {
    	free_ep_req(hidg->in_ep, hidg->req);
    	goto try_again;
    }
    
    [...]
    
    status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
    =>
    	[...]
    	=> usb_gadget_giveback_request
    		=>
    		f_hidg_req_complete
    			=>
    			spin_lock_irqsave(&hidg->write_spinlock, flags); // second acquire
    
    Note that this happens because dwc3 would call ->complete() on a
    failed usb_ep_queue() due to failed Start Transfer command. This is,
    anyway, a theoretical situation because dwc3 currently uses "No
    Response Update Transfer" command for Bulk and Interrupt endpoints.
    
    It's still good to make this case impossible to happen even if the "No
    Reponse Update Transfer" command is changed.
    Reported-by: default avatarTuba Yavuz <tuba@ece.ufl.edu>
    Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
    Cc: stable <stable@vger.kernel.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    c91815b5
gadget.c 83.2 KB