Merge "usb: f_qdss: Fix watchdog bark issue on wait_for_completion"

This commit is contained in:
qctecmdr 2020-05-09 23:44:37 -07:00 • committed by Gerrit - the friendly Code Review server
commit bfc032ea12
4 changed files with 68 additions and 124 deletions

View file

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

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

View file

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

View file

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