usb: gadget: u_serial: Dequeue request on gserial_disconnect

Consider a case where, during bus_reset or composition switch,
due to some reason ENDXFER command timed out. Now, gadget driver
won't be giving back the requests to function driver because of
the timeout since controller can still access those requests.
During function_disable gadget driver expects function driver to
dequeue the requests so that the lists maintained by both gadget
driver and function driver should free up all the request.
Currently u_serial driver is just freeing the requests from
read/write pool without any dequeue which is causing
inconsistencies.

Fix this by dequeueing requests from read/write pool on
gserial_disconnect.

Change-Id: I714c7fe681d42a68c864bf0e90748f117b258548
Signed-off-by: Pratham Pratap <quic_ppratap@quicinc.com>
This commit is contained in:
Pratham Pratap 2021-11-30 13:24:29 +05:30 • committed by Gerrit - the friendly Code Review server
commit 83626bc1f4

View file

@ -115,6 +115,8 @@ struct gs_port {
struct list_head write_pool;
int write_started;
int write_allocated;
struct list_head queued_read_pool;
struct list_head queued_write_pool;
struct kfifo port_write_buf;
wait_queue_head_t drain_wait; /* wait while writes drain */
bool write_busy;
@ -252,7 +254,7 @@ __acquires(&port->port_lock)
do_tty_wake = true;
req->length = len;
list_del(&req->list);
list_move_tail(&req->list, &port->queued_write_pool);
req->zero = kfifo_is_empty(&port->port_write_buf);
pr_vdebug("ttyGS%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
@ -317,7 +319,7 @@ __acquires(&port->port_lock)
break;
req = list_entry(pool->next, struct usb_request, list);
list_del(&req->list);
list_move_tail(&req->list, &port->queued_read_pool);
req->length = out->maxpacket;
/* drop lock while we call out; the controller driver
@ -1162,6 +1164,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
INIT_LIST_HEAD(&port->read_pool);
INIT_LIST_HEAD(&port->read_queue);
INIT_LIST_HEAD(&port->write_pool);
INIT_LIST_HEAD(&port->queued_read_pool);
INIT_LIST_HEAD(&port->queued_write_pool);
port->port_num = port_num;
port->port_line_coding = *coding;
@ -1366,6 +1370,26 @@ void gserial_disconnect(struct gserial *gser)
/* tell the TTY glue not to do I/O here any more */
spin_lock_irqsave(&port->port_lock, flags);
while (!list_empty(&port->queued_read_pool)) {
struct usb_request *read_req;
read_req = list_first_entry(&port->queued_read_pool,
struct usb_request, list);
spin_unlock(&port->port_lock);
usb_ep_dequeue(port->port_usb->out, read_req);
spin_lock(&port->port_lock);
}
while (!list_empty(&port->queued_write_pool)) {
struct usb_request *write_req;
write_req = list_first_entry(&port->queued_write_pool,
struct usb_request, list);
spin_unlock(&port->port_lock);
usb_ep_dequeue(port->port_usb->in, write_req);
spin_lock(&port->port_lock);
}
/* REVISIT as above: how best to track this? */
port->port_line_coding = gser->port_line_coding;