usb: gadget: cser: Requeue OUT USB requests if ECONNRESET is received

During enumeration, the host can send a clear feature EP_HALT.  When
the UDC receives this command, it will cancel any pending requests and
return -ECONNRESET to the function driver.  Since the clear EP_HALT
occurs after the cser driver has already submitted the OUT USB reqs,
there is no other method to restart these transfers.  Resubmit OUT
reqs specifically when ECONNRESET is seen.

Change-Id: I925170d389048f84579c9b53128effdbef5c9d6a
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
This commit is contained in:
Wesley Cheng
2021-02-11 01:26:50 -08:00
parent 5f60ac119f
commit 51ada3a994

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011, 2013-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2011, 2013-2021, The Linux Foundation. All rights reserved.
* Linux Foundation chooses to take subject only to the GPLv2 license terms,
* and distributes only under these terms.
*
@@ -949,6 +949,7 @@ static void usb_cser_read_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_cdev *port = ep->driver_data;
unsigned long flags;
int ret;
pr_debug("ep:(%pK)(%s) port:%p req_status:%d req->actual:%u\n",
ep, ep->name, port, req->status, req->actual);
@@ -958,7 +959,25 @@ static void usb_cser_read_complete(struct usb_ep *ep, struct usb_request *req)
}
spin_lock_irqsave(&port->port_lock, flags);
if (!port->port_open || req->status || !req->actual) {
if (!port->port_open) {
list_add_tail(&req->list, &port->read_pool);
spin_unlock_irqrestore(&port->port_lock, flags);
return;
}
if (req->status || !req->actual) {
/*
* ECONNRESET can be returned when host issues clear EP halt,
* restart OUT requests if so.
*/
if (req->status == -ECONNRESET) {
spin_unlock_irqrestore(&port->port_lock, flags);
ret = usb_ep_queue(ep, req, GFP_KERNEL);
if (!ret)
return;
spin_lock_irqsave(&port->port_lock, flags);
}
list_add_tail(&req->list, &port->read_pool);
spin_unlock_irqrestore(&port->port_lock, flags);
return;