From 4aba93633a3373df7ef095c0a9272ebc127acf10 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Tue, 13 Jul 2021 16:30:03 -0700 Subject: [PATCH] usb: f_qdss: Flush connect_work in qdss close When qdss open and close are called back to back at a high rate, connect_work that gets queued in qdss open can execute after qdss close. For qdss HW path the connect work that gets scheduled as part of the next qdss open results in ep config failure as the ep is already configured during previous connect work. Now before queuing the request if there is a qdss close it would reset the dbm ep configuration thus routing this request via software path instead of dbm path. The subsequent dequeue would lead to a NULL pointer dereference of completion callback. Fix this by flushing connect_work as part of qdss close for graceful termination. Change-Id: I8edf73ea1f87e297297828e6e25c7c14a422ec3a Signed-off-by: Elson Roy Serrao --- drivers/usb/gadget/function/f_qdss.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 5fea4e4f45c8..d92ff5dee4a9 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -591,8 +591,8 @@ static void usb_qdss_connect_work(struct work_struct *work) qdss = container_of(work, struct f_qdss, connect_w); - /* If qdss is closed or cable is removed, discard connect_work */ - if (qdss->qdss_close || qdss->usb_connected == 0) { + /* If cable is removed, discard connect_work */ + if (qdss->usb_connected == 0) { cancel_work_sync(&qdss->disconnect_w); return; } @@ -927,6 +927,8 @@ void usb_qdss_close(struct usb_qdss_ch *ch) if (qdss->endless_req) { spin_unlock_irqrestore(&channel_lock, flags); + /* Flush connect work before proceeding with de-queue */ + flush_work(&qdss->connect_w); usb_ep_dequeue(qdss->port.data, qdss->endless_req); spin_lock_irqsave(&channel_lock, flags); }