diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c index 6fcff596935d..1aa933e2b959 100644 --- a/drivers/hwtracing/coresight/coresight-byte-cntr.c +++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c @@ -519,7 +519,7 @@ void usb_bypass_notifier(void *priv, unsigned int event, switch (event) { case USB_QDSS_CONNECT: - usb_qdss_alloc_req(ch, USB_BUF_NUM, 0); + usb_qdss_alloc_req(ch, USB_BUF_NUM); usb_bypass_start(drvdata); queue_work(drvdata->usb_wq, &(drvdata->read_work)); break; diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 0a9d15216f01..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; @@ -239,7 +240,10 @@ static void qdss_write_complete(struct usb_ep *ep, } spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, list_pool); + if (!qdss->debug_inface_enabled) + 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; @@ -250,32 +254,11 @@ static void qdss_write_complete(struct usb_ep *ep, qdss->ch.notify(qdss->ch.priv, state, d_req, NULL); } -static void qdss_ctrl_read_complete(struct usb_ep *ep, - struct usb_request *req) -{ - struct f_qdss *qdss = ep->driver_data; - struct qdss_request *d_req = req->context; - unsigned long flags; - - pr_debug("%s\n", __func__); - - d_req->actual = req->actual; - d_req->status = req->status; - - spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->ctrl_read_pool); - spin_unlock_irqrestore(&qdss->lock, flags); - - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_READ_DONE, d_req, - NULL); -} - 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__); @@ -286,33 +269,31 @@ 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); - list_for_each_safe(act, tmp, &qdss->ctrl_read_pool) { - req = list_entry(act, struct usb_request, list); - list_del(&req->list); - usb_ep_free_request(qdss->port.ctrl_out, req); } } EXPORT_SYMBOL(usb_qdss_free_req); -int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf, - int no_read_buf) +int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf) { struct f_qdss *qdss = ch->priv_usb; struct usb_request *req; struct usb_ep *in; struct list_head *list_pool; int i; + struct qdss_req *qreq; pr_debug("%s\n", __func__); @@ -321,10 +302,8 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf, return -ENODEV; } - if ((qdss->debug_inface_enabled && - (no_write_buf <= 0 || no_read_buf <= 0)) || - (!qdss->debug_inface_enabled && - (no_write_buf <= 0 || no_read_buf))) { + if ((qdss->debug_inface_enabled && no_write_buf <= 0) || + (!qdss->debug_inface_enabled && no_write_buf <= 0)) { pr_err("%s: missing params\n", __func__); return -ENODEV; } @@ -338,23 +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); - } - - for (i = 0; i < no_read_buf; i++) { - req = usb_ep_alloc_request(qdss->port.ctrl_out, GFP_ATOMIC); - if (!req) { - pr_err("%s: ctrl_out allocation err\n", __func__); - goto fail; - } - req->complete = qdss_ctrl_read_complete; - list_add_tail(&req->list, &qdss->ctrl_read_pool); + list_add_tail(&qreq->list, list_pool); + init_completion(&qreq->write_done); } return 0; @@ -807,65 +780,21 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name) spin_unlock_irqrestore(&qdss_lock, flags); spin_lock_init(&qdss->lock); - INIT_LIST_HEAD(&qdss->ctrl_read_pool); INIT_LIST_HEAD(&qdss->ctrl_write_pool); INIT_LIST_HEAD(&qdss->data_write_pool); + INIT_LIST_HEAD(&qdss->queued_data_pool); INIT_WORK(&qdss->connect_w, usb_qdss_connect_work); INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work); return qdss; } -int usb_qdss_ctrl_read(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; - - pr_debug("%s\n", __func__); - - if (!qdss) - return -ENODEV; - - spin_lock_irqsave(&qdss->lock, flags); - - if (qdss->usb_connected == 0) { - spin_unlock_irqrestore(&qdss->lock, flags); - return -EIO; - } - - if (list_empty(&qdss->ctrl_read_pool)) { - spin_unlock_irqrestore(&qdss->lock, flags); - pr_err("error: %s list is empty\n", __func__); - return -EAGAIN; - } - - req = list_first_entry(&qdss->ctrl_read_pool, struct usb_request, list); - list_del(&req->list); - spin_unlock_irqrestore(&qdss->lock, flags); - - req->buf = d_req->buf; - req->length = d_req->length; - req->context = d_req; - - if (usb_ep_queue(qdss->port.ctrl_out, req, GFP_ATOMIC)) { - /* If error add the link to linked list again*/ - spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->ctrl_read_pool); - spin_unlock_irqrestore(&qdss->lock, flags); - pr_err("qdss usb_ep_queue failed\n"); - return -EIO; - } - - return 0; -} -EXPORT_SYMBOL(usb_qdss_ctrl_read); - 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__); @@ -885,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; @@ -910,15 +840,16 @@ 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_ctrl_write\n"); + pr_debug("usb_qdss_data_write\n"); if (!qdss) return -ENODEV; spin_lock_irqsave(&qdss->lock, flags); - if (qdss->usb_connected == 0) { + if (qdss->qdss_close || qdss->usb_connected == 0) { spin_unlock_irqrestore(&qdss->lock, flags); return -EIO; } @@ -929,20 +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_del(&req->list); + 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(&qreq->write_done); if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) { spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->data_write_pool); + /* Remove from queued pool and add back to data pool */ + 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; @@ -989,6 +924,7 @@ struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, ch->priv = priv; ch->notify = notify; ch->app_conn = 1; + qdss->qdss_close = false; spin_unlock_irqrestore(&qdss_lock, flags); /* the case USB cabel was connected before qdss called qdss_open */ @@ -1005,6 +941,7 @@ void usb_qdss_close(struct usb_qdss_ch *ch) struct usb_gadget *gadget; unsigned long flags; int status; + struct qdss_req *qreq; pr_debug("%s\n", __func__); @@ -1017,6 +954,17 @@ void usb_qdss_close(struct usb_qdss_ch *ch) } qdss = ch->priv_usb; + qdss->qdss_close = true; + while (!list_empty(&qdss->queued_data_pool)) { + qreq = list_first_entry(&qdss->queued_data_pool, + struct qdss_req, list); + spin_unlock_irqrestore(&qdss_lock, flags); + usb_ep_dequeue(qdss->port.data, qreq->usb_req); + wait_for_completion(&qreq->write_done); + spin_lock_irqsave(&qdss_lock, flags); + } + + usb_qdss_free_req(ch); ch->priv_usb = NULL; if (!qdss || !qdss->usb_connected || !strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) { diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index 13186d6e8988..cf48773f13f0 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -49,11 +49,11 @@ struct f_qdss { bool debug_inface_enabled; struct usb_request *endless_req; struct usb_qdss_ch ch; - struct list_head ctrl_read_pool; struct list_head ctrl_write_pool; /* for mdm channel SW path */ struct list_head data_write_pool; + struct list_head queued_data_pool; struct work_struct connect_w; struct work_struct disconnect_w; @@ -62,6 +62,7 @@ struct f_qdss { unsigned int ctrl_in_enabled:1; unsigned int ctrl_out_enabled:1; struct workqueue_struct *wq; + bool qdss_close; }; struct usb_qdss_opts { diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h index ce1667a661ef..c5f22c5f4abc 100644 --- a/include/linux/usb/usb_qdss.h +++ b/include/linux/usb/usb_qdss.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2013, 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2017-2020 The Linux Foundation. All rights reserved. */ #ifndef __LINUX_USB_QDSS_H @@ -42,17 +42,22 @@ 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, struct qdss_request *d_req, struct usb_qdss_ch *ch)); void usb_qdss_close(struct usb_qdss_ch *ch); -int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int n_write, int n_read); +int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int n_write); void usb_qdss_free_req(struct usb_qdss_ch *ch); -int usb_qdss_read(struct usb_qdss_ch *ch, struct qdss_request *d_req); int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req); int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req); -int usb_qdss_ctrl_read(struct usb_qdss_ch *ch, struct qdss_request *d_req); #else static inline struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, void (*n)(void *, unsigned int event, @@ -61,11 +66,6 @@ static inline struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, return ERR_PTR(-ENODEV); } -static inline int usb_qdss_read(struct usb_qdss_ch *c, struct qdss_request *d) -{ - return -ENODEV; -} - static inline int usb_qdss_write(struct usb_qdss_ch *c, struct qdss_request *d) { return -ENODEV; @@ -77,11 +77,6 @@ static inline int usb_qdss_ctrl_write(struct usb_qdss_ch *c, return -ENODEV; } -static inline int usb_qdss_ctrl_read(struct usb_qdss_ch *c, - struct qdss_request *d) -{ - return -ENODEV; -} static inline int usb_qdss_alloc_req(struct usb_qdss_ch *c, int n_wr, int n_rd) { return -ENODEV;