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 & bridge
driver from initializing complete. Initialization of
completion now occurs from alloc_req.
Change-Id: Ie6b1cd445ed6bb38c1a555f6c4c41068090e4fac
Signed-off-by: Udipto Goswami <ugoswami@codeaurora.org>
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c
index d0b7a89..6353106 100644
--- a/drivers/hwtracing/coresight/coresight-byte-cntr.c
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c
@@ -340,8 +340,6 @@
goto out;
}
- init_completion(&usb_req->write_done);
-
actual = tmc_etr_buf_get_data(etr_buf, drvdata->offset,
req_size, &usb_req->buf);
usb_req->length = actual;
@@ -425,7 +423,6 @@
sizeof(*usb_req), GFP_KERNEL);
if (!usb_req)
return;
- init_completion(&usb_req->write_done);
usb_req->sg = devm_kzalloc(tmcdrvdata->dev,
sizeof(*(usb_req->sg)) * req_sg_num,
GFP_KERNEL);
diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c
index d9e1422..4d15790 100644
--- a/drivers/soc/qcom/qdss_bridge.c
+++ b/drivers/soc/qcom/qdss_bridge.c
@@ -108,7 +108,6 @@
buf = kzalloc(drvdata->mtu, GFP_KERNEL);
usb_req = kzalloc(sizeof(*usb_req), GFP_KERNEL);
- init_completion(&usb_req->write_done);
entry->buf = buf;
entry->usb_req = usb_req;
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 4742b9b..329bee7 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -219,7 +219,8 @@
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,9 +240,9 @@
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;
@@ -255,8 +256,8 @@
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;
qdss = ch->priv_usb;
if (!qdss) {
@@ -267,15 +268,19 @@
qdss_log("%s: channel name = %s\n", __func__, qdss->ch.name);
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);
@@ -287,6 +292,7 @@
struct usb_ep *in;
struct list_head *list_pool;
int i;
+ struct qdss_req *qreq;
qdss_log("%s\n", __func__);
@@ -310,13 +316,17 @@
}
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 @@
struct f_qdss *qdss = ch->priv_usb;
unsigned long flags;
struct usb_request *req = NULL;
+ struct qdss_req *qreq;
qdss_log("%s\n", __func__);
@@ -803,17 +814,18 @@
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 @@
struct f_qdss *qdss = ch->priv_usb;
unsigned long flags;
struct usb_request *req = NULL;
+ struct qdss_req *qreq;
qdss_log("usb_qdss_data_write\n");
@@ -847,23 +860,24 @@
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 @@
struct usb_gadget *gadget;
unsigned long flags;
int status;
- struct usb_request *req;
- struct qdss_request *d_req;
+ struct qdss_req *qreq;
qdss_log("%s\n", __func__);
@@ -937,12 +950,11 @@
goto close;
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);
}
usb_qdss_free_req(ch);
diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h
index 8af6f6e..645d6f6 100644
--- a/include/linux/usb/usb_qdss.h
+++ b/include/linux/usb/usb_qdss.h
@@ -20,7 +20,6 @@
struct scatterlist *sg;
unsigned int num_sgs;
unsigned int num_mapped_sgs;
- struct completion write_done;
};
struct usb_qdss_ch {
@@ -41,6 +40,13 @@
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,