From 5a2932496a1186c671e44746e779f470bec25a34 Mon Sep 17 00:00:00 2001 From: Udipto Goswami Date: Wed, 6 May 2020 18:24:32 -0700 Subject: [PATCH] usb: f_qdss: Fix watchdog bark issue on wait_for_completion The coresight driver is freeing up d_req as part of notify from write_complete. Accessing write_done form qdss_close, wait_for_completion will be stuck there causing watchdog bark. Fix this by making f_qdss independent of coresight driver from initializing complete. Initialization of completion now occurs from alloc_req. Change-Id: Ie6b1cd445ed6bb38c1a555f6c4c41068090e4fac Signed-off-by: Udipto Goswami Signed-off-by: Mayank Rana --- drivers/usb/gadget/function/f_qdss.c | 70 ++++++++++++++++------------ include/linux/usb/usb_qdss.h | 8 +++- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 7659ae430bfb..7b660241c57c 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -220,7 +220,8 @@ static void qdss_write_complete(struct usb_ep *ep, struct usb_request *req) { struct f_qdss *qdss = ep->driver_data; - struct qdss_request *d_req = req->context; + struct qdss_req *qreq = req->context; + struct qdss_request *d_req = qreq->qdss_req; struct usb_ep *in; struct list_head *list_pool; enum qdss_state state; @@ -240,9 +241,9 @@ static void qdss_write_complete(struct usb_ep *ep, spin_lock_irqsave(&qdss->lock, flags); if (!qdss->debug_inface_enabled) - list_del(&req->list); - list_add_tail(&req->list, list_pool); - complete(&d_req->write_done); + list_del(&qreq->list); + list_add_tail(&qreq->list, list_pool); + complete(&qreq->write_done); if (req->length != 0) { d_req->actual = req->actual; d_req->status = req->status; @@ -256,8 +257,8 @@ static void qdss_write_complete(struct usb_ep *ep, void usb_qdss_free_req(struct usb_qdss_ch *ch) { struct f_qdss *qdss; - struct usb_request *req; struct list_head *act, *tmp; + struct qdss_req *qreq; pr_debug("%s\n", __func__); @@ -268,15 +269,19 @@ void usb_qdss_free_req(struct usb_qdss_ch *ch) } list_for_each_safe(act, tmp, &qdss->data_write_pool) { - req = list_entry(act, struct usb_request, list); - list_del(&req->list); - usb_ep_free_request(qdss->port.data, req); + qreq = list_entry(act, struct qdss_req, list); + list_del(&qreq->list); + usb_ep_free_request(qdss->port.data, qreq->usb_req); + kfree(qreq); + } list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) { - req = list_entry(act, struct usb_request, list); - list_del(&req->list); - usb_ep_free_request(qdss->port.ctrl_in, req); + qreq = list_entry(act, struct qdss_req, list); + list_del(&qreq->list); + usb_ep_free_request(qdss->port.ctrl_in, qreq->usb_req); + kfree(qreq); + } } EXPORT_SYMBOL(usb_qdss_free_req); @@ -288,6 +293,7 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf) struct usb_ep *in; struct list_head *list_pool; int i; + struct qdss_req *qreq; pr_debug("%s\n", __func__); @@ -311,13 +317,17 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf) } for (i = 0; i < no_write_buf; i++) { + qreq = kzalloc(sizeof(struct qdss_req), GFP_KERNEL); req = usb_ep_alloc_request(in, GFP_ATOMIC); if (!req) { pr_err("%s: ctrl_in allocation err\n", __func__); goto fail; } + qreq->usb_req = req; + req->context = qreq; req->complete = qdss_write_complete; - list_add_tail(&req->list, list_pool); + list_add_tail(&qreq->list, list_pool); + init_completion(&qreq->write_done); } return 0; @@ -784,6 +794,7 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) struct f_qdss *qdss = ch->priv_usb; unsigned long flags; struct usb_request *req = NULL; + struct qdss_req *qreq; pr_debug("%s\n", __func__); @@ -803,17 +814,18 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) return -EAGAIN; } - req = list_first_entry(&qdss->ctrl_write_pool, struct usb_request, + qreq = list_first_entry(&qdss->ctrl_write_pool, struct qdss_req, list); - list_del(&req->list); + list_del(&qreq->list); spin_unlock_irqrestore(&qdss->lock, flags); + qreq->qdss_req = d_req; + req = qreq->usb_req; req->buf = d_req->buf; req->length = d_req->length; - req->context = d_req; if (usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC)) { spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->ctrl_write_pool); + list_add_tail(&qreq->list, &qdss->ctrl_write_pool); spin_unlock_irqrestore(&qdss->lock, flags); pr_err("%s usb_ep_queue failed\n", __func__); return -EIO; @@ -828,6 +840,7 @@ int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) struct f_qdss *qdss = ch->priv_usb; unsigned long flags; struct usb_request *req = NULL; + struct qdss_req *qreq; pr_debug("usb_qdss_data_write\n"); @@ -847,23 +860,24 @@ int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) return -EAGAIN; } - req = list_first_entry(&qdss->data_write_pool, struct usb_request, + qreq = list_first_entry(&qdss->data_write_pool, struct qdss_req, list); - list_move_tail(&req->list, &qdss->queued_data_pool); + list_move_tail(&qreq->list, &qdss->queued_data_pool); spin_unlock_irqrestore(&qdss->lock, flags); + qreq->qdss_req = d_req; + req = qreq->usb_req; req->buf = d_req->buf; req->length = d_req->length; - req->context = d_req; req->sg = d_req->sg; req->num_sgs = d_req->num_sgs; req->num_mapped_sgs = d_req->num_mapped_sgs; - reinit_completion(&d_req->write_done); + reinit_completion(&qreq->write_done); if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) { spin_lock_irqsave(&qdss->lock, flags); /* Remove from queued pool and add back to data pool */ - list_move_tail(&req->list, &qdss->data_write_pool); - complete(&d_req->write_done); + list_move_tail(&qreq->list, &qdss->data_write_pool); + complete(&qreq->write_done); spin_unlock_irqrestore(&qdss->lock, flags); pr_err("qdss usb_ep_queue failed\n"); return -EIO; @@ -927,8 +941,7 @@ void usb_qdss_close(struct usb_qdss_ch *ch) struct usb_gadget *gadget; unsigned long flags; int status; - struct usb_request *req; - struct qdss_request *d_req; + struct qdss_req *qreq; pr_debug("%s\n", __func__); @@ -943,12 +956,11 @@ void usb_qdss_close(struct usb_qdss_ch *ch) qdss = ch->priv_usb; qdss->qdss_close = true; while (!list_empty(&qdss->queued_data_pool)) { - req = list_first_entry(&qdss->queued_data_pool, - struct usb_request, list); - d_req = req->context; + qreq = list_first_entry(&qdss->queued_data_pool, + struct qdss_req, list); spin_unlock_irqrestore(&qdss_lock, flags); - usb_ep_dequeue(qdss->port.data, req); - wait_for_completion(&d_req->write_done); + usb_ep_dequeue(qdss->port.data, qreq->usb_req); + wait_for_completion(&qreq->write_done); spin_lock_irqsave(&qdss_lock, flags); } diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h index 9cdb005cfca7..c5f22c5f4abc 100644 --- a/include/linux/usb/usb_qdss.h +++ b/include/linux/usb/usb_qdss.h @@ -22,7 +22,6 @@ struct qdss_request { struct scatterlist *sg; unsigned int num_sgs; unsigned int num_mapped_sgs; - struct completion write_done; }; struct usb_qdss_ch { @@ -43,6 +42,13 @@ enum qdss_state { USB_QDSS_CTRL_WRITE_DONE, }; +struct qdss_req { + struct usb_request *usb_req; + struct completion write_done; + struct qdss_request *qdss_req; + struct list_head list; +}; + #if IS_ENABLED(CONFIG_USB_F_QDSS) struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, void (*notify)(void *priv, unsigned int event,