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 <ugoswami@codeaurora.org>
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
This commit is contained in:
Udipto Goswami 2020-05-06 18:24:32 -07:00 • committed by Mayank Rana
commit 5a2932496a
2 changed files with 48 additions and 30 deletions

View file

@ -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);
}

View file

@ -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,