summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVijayavardhan Vennapusa <vvreddy@codeaurora.org>2013-02-14 16:33:30 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:06:15 -0700
commit72dfd991832c7b09e67c627d3b08a735c41dfd23 (patch)
treebda9dcee96f2c01b8dc0fe14278c643047f813b3
parent2799624a41c8b70956c083904503a9687483914e (diff)
USB: dwc3: Add debug support for DWC3 driver
Add support for DWC3 driver to dump requests in SW queue list, requests queued to USB HW and trb list as well. Also add support for logging endpoint events through debugfs. Enable logging of EP0 control events by default. Example: To capture 2 in endpoint events echo -n 4 > /sys/module/dwc3/parameters/ep_addr_txdbg_mask To capture 3 out endpoint events echo -n 8 > /sys/module/dwc3/parameters/ep_addr_rxdbg_mask To print debug log events on endpoints cat /sys/kernel/debug/dwc3/events To dump requests in SW queue list for 6 out endpoint echo 6 0 > /sys/kernel/debug/dwc3/requests cat /sys/kernel/debug/dwc3/requests To dump requests queued to USB HW for 8 in endpoint echo 8 1 > /sys/kernel/debug/dwc3/queued_reqs cat /sys/kernel/debug/dwc3/queued_reqs To dump TRBs for 9 in endpoint echo 9 1 > /sys/kernel/debug/dwc3/trbs cat /sys/kernel/debug/dwc3/trbs Change-Id: I84e963b8299a1af76de9a35a6ea46ec34b9fe79e Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org> Signed-off-by: Jack Pham <jackp@codeaurora.org>
-rw-r--r--drivers/usb/dwc3/core.c21
-rw-r--r--drivers/usb/dwc3/core.h7
-rw-r--r--drivers/usb/dwc3/debug.h20
-rw-r--r--drivers/usb/dwc3/debugfs.c428
-rw-r--r--drivers/usb/dwc3/ep0.c18
-rw-r--r--drivers/usb/dwc3/gadget.c58
6 files changed, 547 insertions, 5 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 22b4797383cd..487c1d84159b 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -803,6 +803,26 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
}
}
+static void (*notify_event) (struct dwc3 *, unsigned);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned))
+{
+ notify_event = notify;
+}
+EXPORT_SYMBOL(dwc3_set_notifier);
+
+int dwc3_notify_event(struct dwc3 *dwc, unsigned event)
+{
+ int ret = 0;
+
+ if (dwc->notify_event)
+ dwc->notify_event(dwc, event);
+ else
+ ret = -ENODEV;
+
+ return ret;
+}
+EXPORT_SYMBOL(dwc3_notify_event);
+
#define DWC3_ALIGN_MASK (16 - 1)
static int dwc3_probe(struct platform_device *pdev)
@@ -829,6 +849,7 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->mem = mem;
dwc->dev = dev;
+ dwc->notify_event = notify_event;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing IRQ\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 36f1cb74588c..aabb7e92c343 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -642,6 +642,7 @@ struct dwc3_scratchpad_array {
__le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
};
+#define DWC3_CONTROLLER_ERROR_EVENT 0
/**
* struct dwc3 - representation of our controller
* @ctrl_req: usb control request which is used for ep0
@@ -842,6 +843,8 @@ struct dwc3 {
const char *hsphy_interface;
+ void (*notify_event) (struct dwc3 *, unsigned);
+
unsigned delayed_status:1;
unsigned ep0_bounced:1;
unsigned ep0_expect_in:1;
@@ -1088,4 +1091,8 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc)
{ }
#endif
+extern void dwc3_set_notifier(
+ void (*notify) (struct dwc3 *dwc3, unsigned event));
+extern void dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
+
#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 07fbc2d94fd4..2cafa949bb12 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -217,9 +217,29 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
#ifdef CONFIG_DEBUG_FS
+extern void dbg_event(u8, const char*, int);
+extern void dbg_print(u8, const char*, int, const char*);
+extern void dbg_done(u8, const u32, int);
+extern void dbg_queue(u8, const struct usb_request*, int);
+extern void dbg_setup(u8, const struct usb_ctrlrequest*);
extern int dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *);
+extern void dbg_print_reg(const char *name, int reg);
#else
+static inline void dbg_event(u8 ep_num, const char *name, int status)
+{ }
+static inline void dbg_print(u8 ep_num, const char *name, int status,
+ const char *extra)
+{ }
+static inline void dbg_done(u8 ep_num, const u32 count, int status)
+{ }
+static inline void dbg_queue(u8 ep_num, const struct usb_request *req,
+ int status)
+{ }
+static inline void dbg_setup(u8 ep_num, const struct usb_ctrlrequest *req)
+{ }
+static inline void dbg_print_reg(const char *name, int reg)
+{ }
static inline int dwc3_debugfs_init(struct dwc3 *d)
{ return 0; }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 9ac37fe1b6a7..703652a4e267 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/ptrace.h>
@@ -618,6 +619,406 @@ static const struct file_operations dwc3_link_state_fops = {
.release = single_release,
};
+static int ep_num;
+static ssize_t dwc3_store_ep_num(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct dwc3 *dwc = s->private;
+ char kbuf[10];
+ unsigned int num, dir;
+ unsigned long flags;
+
+ memset(kbuf, 0, 10);
+
+ if (copy_from_user(kbuf, ubuf, count > 10 ? 10 : count))
+ return -EFAULT;
+
+ if (sscanf(kbuf, "%u %u", &num, &dir) != 2)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ep_num = (num << 1) + dir;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return count;
+}
+
+static int dwc3_ep_req_list_show(struct seq_file *s, void *unused)
+{
+ struct dwc3 *dwc = s->private;
+ struct dwc3_ep *dep;
+ struct dwc3_request *req = NULL;
+ struct list_head *ptr = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dep = dwc->eps[ep_num];
+
+ seq_printf(s, "%s request list: flags: 0x%x\n", dep->name, dep->flags);
+ list_for_each(ptr, &dep->request_list) {
+ req = list_entry(ptr, struct dwc3_request, list);
+
+ seq_printf(s,
+ "req:0x%p len: %d sts: %d dma:0x%pa num_sgs: %d\n",
+ req, req->request.length, req->request.status,
+ &req->request.dma, req->request.num_sgs);
+ }
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static int dwc3_ep_req_list_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_ep_req_list_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_ep_req_list_fops = {
+ .open = dwc3_ep_req_list_open,
+ .write = dwc3_store_ep_num,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dwc3_ep_queued_req_show(struct seq_file *s, void *unused)
+{
+ struct dwc3 *dwc = s->private;
+ struct dwc3_ep *dep;
+ struct dwc3_request *req = NULL;
+ struct list_head *ptr = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dep = dwc->eps[ep_num];
+
+ seq_printf(s, "%s queued reqs to HW: flags:0x%x\n", dep->name,
+ dep->flags);
+ list_for_each(ptr, &dep->req_queued) {
+ req = list_entry(ptr, struct dwc3_request, list);
+
+ seq_printf(s,
+ "req:0x%p len:%d sts:%d dma:%pa nsg:%d trb:0x%p\n",
+ req, req->request.length, req->request.status,
+ &req->request.dma, req->request.num_sgs, req->trb);
+ }
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static int dwc3_ep_queued_req_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_ep_queued_req_show, inode->i_private);
+}
+
+const struct file_operations dwc3_ep_req_queued_fops = {
+ .open = dwc3_ep_queued_req_open,
+ .write = dwc3_store_ep_num,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dwc3_ep_trbs_show(struct seq_file *s, void *unused)
+{
+ struct dwc3 *dwc = s->private;
+ struct dwc3_ep *dep;
+ struct dwc3_trb *trb;
+ unsigned long flags;
+ int j;
+
+ if (!ep_num)
+ return 0;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dep = dwc->eps[ep_num];
+
+ seq_printf(s, "%s trb pool: flags:0x%x freeslot:%d busyslot:%d\n",
+ dep->name, dep->flags, dep->free_slot, dep->busy_slot);
+ for (j = 0; j < DWC3_TRB_NUM; j++) {
+ trb = &dep->trb_pool[j];
+ seq_printf(s, "trb:0x%p bph:0x%x bpl:0x%x size:0x%x ctrl: %x\n",
+ trb, trb->bph, trb->bpl, trb->size, trb->ctrl);
+ }
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static int dwc3_ep_trbs_list_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_ep_trbs_show, inode->i_private);
+}
+
+const struct file_operations dwc3_ep_trb_list_fops = {
+ .open = dwc3_ep_trbs_list_open,
+ .write = dwc3_store_ep_num,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static unsigned int ep_addr_rxdbg_mask = 1;
+module_param(ep_addr_rxdbg_mask, uint, S_IRUGO | S_IWUSR);
+static unsigned int ep_addr_txdbg_mask = 1;
+module_param(ep_addr_txdbg_mask, uint, S_IRUGO | S_IWUSR);
+
+/* Maximum debug message length */
+#define DBG_DATA_MSG 64UL
+
+/* Maximum number of messages */
+#define DBG_DATA_MAX 2048UL
+
+static struct {
+ char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
+ unsigned idx; /* index */
+ unsigned tty; /* print to console? */
+ rwlock_t lck; /* lock */
+} dbg_dwc3_data = {
+ .idx = 0,
+ .tty = 0,
+ .lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static inline void __maybe_unused dbg_dec(unsigned *idx)
+{
+ *idx = (*idx - 1) % DBG_DATA_MAX;
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static inline void dbg_inc(unsigned *idx)
+{
+ *idx = (*idx + 1) % DBG_DATA_MAX;
+}
+
+#define TIME_BUF_LEN 20
+/*get_timestamp - returns time of day in us */
+static char *get_timestamp(char *tbuf)
+{
+ unsigned long long t;
+ unsigned long nanosec_rem;
+
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000)/1000;
+ scnprintf(tbuf, TIME_BUF_LEN, "[%5lu.%06lu] ", (unsigned long)t,
+ nanosec_rem);
+ return tbuf;
+}
+
+static int allow_dbg_print(u8 ep_num)
+{
+ int dir, num;
+
+ /* allow bus wide events */
+ if (ep_num == 0xff)
+ return 1;
+
+ dir = ep_num & 0x1;
+ num = ep_num >> 1;
+ num = 1 << num;
+
+ if (dir && (num & ep_addr_txdbg_mask))
+ return 1;
+ if (!dir && (num & ep_addr_rxdbg_mask))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * dbg_print: prints the common part of the event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ * @extra: extra information
+ */
+void dbg_print(u8 ep_num, const char *name, int status, const char *extra)
+{
+ unsigned long flags;
+ char tbuf[TIME_BUF_LEN];
+
+ if (!allow_dbg_print(ep_num))
+ return;
+
+ write_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+ scnprintf(dbg_dwc3_data.buf[dbg_dwc3_data.idx], DBG_DATA_MSG,
+ "%s\t? %02X %-12.12s %4i ?\t%s\n",
+ get_timestamp(tbuf), ep_num, name, status, extra);
+
+ dbg_inc(&dbg_dwc3_data.idx);
+
+ write_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+ if (dbg_dwc3_data.tty != 0)
+ pr_notice("%s\t? %02X %-7.7s %4i ?\t%s\n",
+ get_timestamp(tbuf), ep_num, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr: endpoint address
+ * @td: transfer descriptor
+ * @status: status
+ */
+void dbg_done(u8 ep_num, const u32 count, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (!allow_dbg_print(ep_num))
+ return;
+
+ scnprintf(msg, sizeof(msg), "%d", count);
+ dbg_print(ep_num, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ */
+void dbg_event(u8 ep_num, const char *name, int status)
+{
+ if (!allow_dbg_print(ep_num))
+ return;
+
+ if (name != NULL)
+ dbg_print(ep_num, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr: endpoint address
+ * @req: USB request
+ * @status: status
+ */
+void dbg_queue(u8 ep_num, const struct usb_request *req, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (!allow_dbg_print(ep_num))
+ return;
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%d %d", !req->no_interrupt, req->length);
+ dbg_print(ep_num, "QUEUE", status, msg);
+ }
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req: setup request
+ */
+void dbg_setup(u8 ep_num, const struct usb_ctrlrequest *req)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (!allow_dbg_print(ep_num))
+ return;
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%02X %02X %04X %04X %d", req->bRequestType,
+ req->bRequest, le16_to_cpu(req->wValue),
+ le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+ dbg_print(ep_num, "SETUP", 0, msg);
+ }
+}
+
+/**
+ * dbg_print_reg: prints a reg value
+ * @name: reg name
+ * @reg: reg value to be printed
+ */
+void dbg_print_reg(const char *name, int reg)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+ scnprintf(dbg_dwc3_data.buf[dbg_dwc3_data.idx], DBG_DATA_MSG,
+ "%s = 0x%08x\n", name, reg);
+
+ dbg_inc(&dbg_dwc3_data.idx);
+
+ write_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+ if (dbg_dwc3_data.tty != 0)
+ pr_notice("%s = 0x%08x\n", name, reg);
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ */
+static ssize_t dwc3_store_events(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ unsigned tty;
+
+ if (buf == NULL) {
+ pr_err("[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+ pr_err("<1|0>: enable|disable console log\n");
+ goto done;
+ }
+
+ dbg_dwc3_data.tty = tty;
+ pr_info("tty = %u", dbg_dwc3_data.tty);
+
+ done:
+ return count;
+}
+
+static int dwc3_gadget_data_events_show(struct seq_file *s, void *unused)
+{
+ unsigned long flags;
+ unsigned i;
+
+ read_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+ i = dbg_dwc3_data.idx;
+ if (strnlen(dbg_dwc3_data.buf[i], DBG_DATA_MSG))
+ seq_printf(s, "%s\n", dbg_dwc3_data.buf[i]);
+ for (dbg_inc(&i); i != dbg_dwc3_data.idx; dbg_inc(&i)) {
+ if (!strnlen(dbg_dwc3_data.buf[i], DBG_DATA_MSG))
+ continue;
+ seq_printf(s, "%s\n", dbg_dwc3_data.buf[i]);
+ }
+
+ read_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+ return 0;
+}
+
+static int dwc3_gadget_data_events_open(struct inode *inode, struct file *f)
+{
+ return single_open(f, dwc3_gadget_data_events_show, inode->i_private);
+}
+
+const struct file_operations dwc3_gadget_dbg_data_fops = {
+ .open = dwc3_gadget_data_events_open,
+ .read = seq_read,
+ .write = dwc3_store_events,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
int dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
@@ -674,6 +1075,33 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
}
}
+ file = debugfs_create_file("trbs", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_ep_trb_list_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ file = debugfs_create_file("requests", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_ep_req_list_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ file = debugfs_create_file("queued_reqs", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_ep_req_queued_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ file = debugfs_create_file("events", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_gadget_dbg_data_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
return 0;
err1:
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 5320e939e090..925c14406804 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -34,6 +34,7 @@
#include "debug.h"
#include "gadget.h"
#include "io.h"
+#include "debug.h"
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
@@ -288,6 +289,7 @@ int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
+ dbg_event(dep->number, "EP0STAL", value);
dwc3_ep0_stall_and_restart(dwc);
return 0;
@@ -773,6 +775,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
}
+ dbg_setup(0x00, ctrl);
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
ret = dwc3_ep0_std_request(dwc, ctrl);
else
@@ -782,8 +785,10 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
dwc->delayed_status = true;
out:
- if (ret < 0)
+ if (ret < 0) {
+ dbg_event(0x0, "ERRSTAL", ret);
dwc3_ep0_stall_and_restart(dwc);
+ }
}
static void dwc3_ep0_complete_data(struct dwc3 *dwc,
@@ -865,7 +870,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
if ((epnum & 1) && ur->actual < ur->length) {
/* for some reason we did not get everything out */
-
+ dbg_event(epnum, "INDATSTAL", 0);
dwc3_ep0_stall_and_restart(dwc);
} else {
dwc3_gadget_giveback(ep0, r, 0);
@@ -910,6 +915,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
if (ret < 0) {
dwc3_trace(trace_dwc3_ep0, "Invalid Test #%d",
dwc->test_mode_nr);
+ dbg_event(0x00, "INVALTEST", ret);
dwc3_ep0_stall_and_restart(dwc);
return;
}
@@ -919,6 +925,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
if (status == DWC3_TRBSTS_SETUP_PENDING)
dwc3_trace(trace_dwc3_ep0, "Setup Pending received");
+ dbg_print(dep->number, "DONE", status, "STATUS");
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
}
@@ -1008,6 +1015,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
false);
}
+ dbg_queue(dep->number, &req->request, ret);
WARN_ON(ret < 0);
}
@@ -1025,13 +1033,16 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
{
+ int ret;
if (dwc->resize_fifos) {
dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
dwc3_gadget_resize_tx_fifos(dwc);
dwc->resize_fifos = 0;
}
- WARN_ON(dwc3_ep0_start_control_status(dep));
+ ret = dwc3_ep0_start_control_status(dep);
+ dbg_print(dep->number, "QUEUE", ret, "STATUS");
+ WARN_ON(ret);
}
static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
@@ -1084,6 +1095,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
dwc3_trace(trace_dwc3_ep0,
"Wrong direction for Data phase");
dwc3_ep0_end_control_data(dwc, dep);
+ dbg_event(epnum, "WRONGDR", 0);
dwc3_ep0_stall_and_restart(dwc);
return;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 57c9924aa9a4..ffa983c84c66 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -33,6 +33,7 @@
#include "debug.h"
#include "core.h"
#include "gadget.h"
+#include "debug.h"
#include "io.h"
/**
@@ -270,6 +271,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
req->request.length, status);
trace_dwc3_gadget_giveback(req);
+ dbg_done(dep->number, req->request.actual, req->request.status);
spin_unlock(&dwc->lock);
usb_gadget_giveback_request(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
@@ -671,6 +673,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
+ dbg_event(dep->number, "ENABLE", ret);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@@ -699,6 +702,7 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_disable(dep);
+ dbg_event(dep->number, "DISABLE", ret);
spin_unlock_irqrestore(&dwc->lock, flags);
return ret;
@@ -910,6 +914,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
if (last_one)
break;
}
+ dbg_queue(dep->number, &req->request, trbs_left);
if (last_one)
break;
@@ -928,6 +933,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
dwc3_prepare_one_trb(dep, req, dma, length,
last_one, false, 0);
+ dbg_queue(dep->number, &req->request, 0);
if (last_one)
break;
}
@@ -968,6 +974,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
}
if (!req) {
dep->flags |= DWC3_EP_PENDING_REQUEST;
+ dbg_event(dep->number, "NO REQ", 0);
return 0;
}
@@ -1012,6 +1019,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
struct dwc3_ep *dep, u32 cur_uf)
{
u32 uf;
+ int ret;
if (list_empty(&dep->request_list)) {
dwc3_trace(trace_dwc3_gadget,
@@ -1024,7 +1032,9 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
/* 4 micro frames in the future */
uf = cur_uf + dep->interval * 4;
- __dwc3_gadget_kick_transfer(dep, uf, 1);
+ ret = __dwc3_gadget_kick_transfer(dep, uf, 1);
+ if (ret < 0)
+ dbg_event(dep->number, "ISOC QUEUE", ret);
}
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@@ -1119,6 +1129,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (!ret)
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+ else if (ret != -EBUSY)
+ dbg_event(dep->number, "XfNR QUEUE", ret);
goto out;
}
@@ -1134,6 +1146,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
WARN_ON_ONCE(!dep->resource_index);
ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index,
false);
+ if (ret && ret != -EBUSY)
+ dbg_event(dep->number, "XfIP QUEUE", ret);
goto out;
}
@@ -1146,9 +1160,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
out:
- if (ret && ret != -EBUSY)
+ if (ret && ret != -EBUSY) {
+ dbg_event(dep->number, "QUEUE err", ret);
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
+ }
if (ret == -EBUSY)
ret = 0;
@@ -1226,6 +1242,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
}
out1:
+ dbg_event(dep->number, "DEQUEUE", 0);
/* giveback the request */
dwc3_gadget_giveback(dep, req, -ECONNRESET);
@@ -1287,6 +1304,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
int ret;
spin_lock_irqsave(&dwc->lock, flags);
+ dbg_event(dep->number, "HALT", value);
ret = __dwc3_gadget_ep_set_halt(dep, value, false);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1301,6 +1319,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
int ret;
spin_lock_irqsave(&dwc->lock, flags);
+ dbg_event(dep->number, "WEDGE", 0);
dep->flags |= DWC3_EP_WEDGE;
if (dep->number == 0 || dep->number == 1)
@@ -1849,6 +1868,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
* request in the request_list.
*/
dep->flags |= DWC3_EP_MISSED_ISOC;
+ dbg_event(dep->number, "MISSED ISOC", status);
} else {
dev_err(dwc->dev, "incomplete IN transfer %s\n",
dep->name);
@@ -2084,6 +2104,7 @@ static void dwc3_suspend_gadget(struct dwc3 *dwc)
{
if (dwc->gadget_driver && dwc->gadget_driver->suspend) {
spin_unlock(&dwc->lock);
+ dbg_event(0xFF, "SUSPEND", 0);
dwc->gadget_driver->suspend(&dwc->gadget);
spin_lock(&dwc->lock);
}
@@ -2093,6 +2114,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
{
if (dwc->gadget_driver && dwc->gadget_driver->resume) {
spin_unlock(&dwc->lock);
+ dbg_event(0xFF, "RESUME", 0);
dwc->gadget_driver->resume(&dwc->gadget);
spin_lock(&dwc->lock);
}
@@ -2207,6 +2229,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
reg &= ~DWC3_DCTL_INITU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ dbg_event(0xFF, "DISCONNECT", 0);
dwc3_disconnect_gadget(dwc);
dwc->start_config_issued = false;
@@ -2251,6 +2274,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
}
dwc3_reset_gadget(dwc);
+ dbg_event(0xFF, "BUS RST", 0);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
@@ -2410,6 +2434,7 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
* implemented.
*/
+ dbg_event(0xFF, "WAKEUP", 0);
dwc->gadget_driver->resume(&dwc->gadget);
}
@@ -2537,6 +2562,32 @@ static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
/* enter hibernation here */
}
+static void dwc3_dump_reg_info(struct dwc3 *dwc)
+{
+ dbg_event(0xFF, "REGDUMP", 0);
+
+ dbg_print_reg("GUSB3PIPCTL", dwc3_readl(dwc->regs,
+ DWC3_GUSB3PIPECTL(0)));
+ dbg_print_reg("GUSB2PHYCONFIG", dwc3_readl(dwc->regs,
+ DWC3_GUSB2PHYCFG(0)));
+ dbg_print_reg("GCTL", dwc3_readl(dwc->regs, DWC3_GCTL));
+ dbg_print_reg("GUCTL", dwc3_readl(dwc->regs, DWC3_GUCTL));
+ dbg_print_reg("GDBGLTSSM", dwc3_readl(dwc->regs, DWC3_GDBGLTSSM));
+ dbg_print_reg("DCFG", dwc3_readl(dwc->regs, DWC3_DCFG));
+ dbg_print_reg("DCTL", dwc3_readl(dwc->regs, DWC3_DCTL));
+ dbg_print_reg("DEVTEN", dwc3_readl(dwc->regs, DWC3_DEVTEN));
+ dbg_print_reg("DSTS", dwc3_readl(dwc->regs, DWC3_DSTS));
+ dbg_print_reg("DALPENA", dwc3_readl(dwc->regs, DWC3_DALEPENA));
+ dbg_print_reg("DGCMD", dwc3_readl(dwc->regs, DWC3_DGCMD));
+
+ dbg_print_reg("OCFG", dwc3_readl(dwc->regs, DWC3_OCFG));
+ dbg_print_reg("OCTL", dwc3_readl(dwc->regs, DWC3_OCTL));
+ dbg_print_reg("OEVT", dwc3_readl(dwc->regs, DWC3_OEVT));
+ dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
+
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
+}
+
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
const struct dwc3_event_devt *event)
{
@@ -2571,12 +2622,15 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
break;
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
dwc3_trace(trace_dwc3_gadget, "Erratic Error");
+ dbg_event(0xFF, "ERROR", 0);
+ dwc3_dump_reg_info(dwc);
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
dwc3_trace(trace_dwc3_gadget, "Command Complete");
break;
case DWC3_DEVICE_EVENT_OVERFLOW:
dwc3_trace(trace_dwc3_gadget, "Overflow");
+ dbg_event(0xFF, "OVERFL", 0);
break;
default:
dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);