@@ -1,9 +1,12 @@
+# define_trace.h needs to know how to find our header
+CFLAGS_trace.o := -I$(src)
+
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC3) += dwc3.o
-dwc3-y := core.o
+dwc3-y := core.o debug.o trace.o
ifneq ($(filter y,$(CONFIG_USB_DWC3_HOST) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
dwc3-y += host.o
new file mode 100644
@@ -0,0 +1,33 @@
+/**
+ * debug.c - DesignWare USB3 DRD Controller Debug/Trace Support
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "debug.h"
+
+void dwc3_trace(void (*trace)(struct va_format *),
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ trace(&vaf);
+
+ va_end(args);
+}
@@ -18,6 +18,9 @@
#include "core.h"
+void dwc3_trace(void (*trace)(struct va_format *),
+ const char *fmt, ...);
+
#ifdef CONFIG_DEBUG_FS
extern int dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *);
@@ -726,6 +726,8 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
if (!dwc->gadget_driver)
goto out;
+ trace_dwc3_ctrl_req(ctrl);
+
len = le16_to_cpu(ctrl->wLength);
if (!len) {
dwc->three_stage_setup = false;
@@ -266,6 +266,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
req, dep->name, req->request.actual,
req->request.length, status);
+ trace_dwc3_gadget_giveback(dwc, req);
spin_unlock(&dwc->lock);
req->request.complete(&dep->endpoint, &req->request);
@@ -800,6 +801,8 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
req->epnum = dep->number;
req->dep = dep;
+ trace_dwc3_alloc_request(dwc, req);
+
return &req->request;
}
@@ -807,7 +810,10 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
struct usb_request *request)
{
struct dwc3_request *req = to_dwc3_request(request);
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ trace_dwc3_free_request(dwc, req);
kfree(req);
}
@@ -1233,6 +1239,7 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
request, ep->name, request->length);
+ trace_dwc3_ep_queue(dwc, req);
spin_lock_irqsave(&dwc->lock, flags);
ret = __dwc3_gadget_ep_queue(dep, req);
@@ -1253,6 +1260,8 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
unsigned long flags;
int ret = 0;
+ trace_dwc3_ep_dequeue(dwc, req);
+
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry(r, &dep->request_list, list) {
@@ -2022,6 +2031,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
dwc3_ep_event_string(event->endpoint_event));
+ dwc3_trace(trace_dwc3_event, "%s: %s", dep->name,
+ dwc3_ep_event_string(event->endpoint_event));
if (epnum == 0 || epnum == 1) {
dwc3_ep0_interrupt(dwc, event);
@@ -2216,6 +2227,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
int reg;
dev_vdbg(dwc->dev, "%s\n", __func__);
+ dwc3_trace(trace_dwc3_event, "disconnect interrupt");
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_INITU1ENA;
@@ -2236,6 +2248,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
u32 reg;
dev_vdbg(dwc->dev, "%s\n", __func__);
+ dwc3_trace(trace_dwc3_event, "reset interrupt");
/*
* WORKAROUND: DWC3 revisions <1.88a have an issue which
@@ -2322,6 +2335,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
u8 speed;
dev_vdbg(dwc->dev, "%s\n", __func__);
+ dwc3_trace(trace_dwc3_event, "connection done interrupt");
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
@@ -2421,6 +2435,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
{
dev_vdbg(dwc->dev, "%s\n", __func__);
+ dwc3_trace(trace_dwc3_event, "wakeup interrupt");
/*
* TODO take core out of low power mode when that's
@@ -2530,6 +2545,10 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
dwc3_gadget_link_string(dwc->link_state),
dwc->link_state, dwc3_gadget_link_string(next), next);
+ dwc3_trace(trace_dwc3_event, "link change: %s [%d] -> %s [%d]",
+ dwc3_gadget_link_string(dwc->link_state),
+ dwc->link_state, dwc3_gadget_link_string(next), next);
+
dwc->link_state = next;
}
@@ -2538,6 +2557,8 @@ static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
{
unsigned int is_ss = evtinfo & BIT(4);
+ dwc3_trace(trace_dwc3_event, "hibernation interrupt");
+
/**
* WORKAROUND: DWC3 revison 2.20a with hibernation support
* have a known issue which can cause USB CV TD.9.23 to fail
@@ -2699,6 +2720,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
if (!count)
return IRQ_NONE;
+ dwc3_trace(trace_dwc3_event, "pending %d events", count);
evt->count = count;
evt->flags |= DWC3_EVENT_PENDING;
@@ -20,27 +20,51 @@
#define __DRIVERS_USB_DWC3_IO_H
#include <linux/io.h>
-
+#include "trace.h"
+#include "debug.h"
#include "core.h"
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
+ u32 offs = offset - DWC3_GLOBALS_REGS_START;
+ u32 value;
+
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
- return readl(base + (offset - DWC3_GLOBALS_REGS_START));
+ value = readl(base + offs);
+
+ /*
+ * When tracing we want to make it easy to find the correct address on
+ * documentation, so we revert it back to the proper addresses, the
+ * same way they are described on SNPS documentation
+ */
+ dwc3_trace(trace_dwc3_readl, "add %p value %08x",
+ base - DWC3_GLOBALS_REGS_START + offset, value);
+
+ return value;
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
+ u32 offs = offset - DWC3_GLOBALS_REGS_START;
+
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
- writel(value, base + (offset - DWC3_GLOBALS_REGS_START));
+ writel(value, base + offs);
+
+ /*
+ * When tracing we want to make it easy to find the correct address on
+ * documentation, so we revert it back to the proper addresses, the
+ * same way they are described on SNPS documentation
+ */
+ dwc3_trace(trace_dwc3_writel, "addr %p value %08x",
+ base - DWC3_GLOBALS_REGS_START + offset, value);
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
new file mode 100644
@@ -0,0 +1,19 @@
+/**
+ * trace.c - DesignWare USB3 DRD Controller Trace Support
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
new file mode 100644
@@ -0,0 +1,130 @@
+/**
+ * trace.h - DesignWare USB3 DRD Controller Trace Support
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM dwc3
+
+#if !defined(__DWC3_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __DWC3_TRACE_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <asm/byteorder.h>
+#include "core.h"
+
+#define DWC3_MSG_MAX 500
+
+DECLARE_EVENT_CLASS(dwc3_log_msg,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf),
+ TP_STRUCT__entry(__dynamic_array(char, msg, DWC3_MSG_MAX)),
+ TP_fast_assign(
+ vsnprintf(__get_str(msg), DWC3_MSG_MAX, vaf->fmt, *vaf->va);
+ ),
+ TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(dwc3_log_msg, dwc3_readl,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(dwc3_log_msg, dwc3_writel,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(dwc3_log_msg, dwc3_event,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_ctrl,
+ TP_PROTO(struct usb_ctrlrequest *ctrl),
+ TP_ARGS(ctrl),
+ TP_STRUCT__entry(
+ __field(struct usb_ctrlrequest *, ctrl)
+ ),
+ TP_fast_assign(
+ __entry->ctrl = ctrl;
+ ),
+ TP_printk("bRequestType %x bRequest %x wValue %02x wIndex %02x wLength %02x",
+ __entry->ctrl->bRequestType, __entry->ctrl->bRequest,
+ le16_to_cpu(__entry->ctrl->wValue), le16_to_cpu(__entry->ctrl->wIndex),
+ le16_to_cpu(__entry->ctrl->wLength)
+ )
+);
+
+DEFINE_EVENT(dwc3_log_ctrl, dwc3_ctrl_req,
+ TP_PROTO(struct usb_ctrlrequest *ctrl),
+ TP_ARGS(ctrl)
+);
+
+DECLARE_EVENT_CLASS(dwc3_log_request,
+ TP_PROTO(struct dwc3 *dwc, struct dwc3_request *req),
+ TP_ARGS(dwc, req),
+ TP_STRUCT__entry(
+ __field(struct dwc3 *, dwc)
+ __field(struct dwc3_request *, req)
+ ),
+ TP_fast_assign(
+ __entry->dwc = dwc;
+ __entry->req = req;
+ ),
+ TP_printk("%s: %s req %p length %u/%u ==> %d",
+ dev_name(__entry->dwc->dev), __entry->req->dep->name,
+ __entry->req, __entry->req->request.actual,
+ __entry->req->request.length, __entry->req->request.status
+ )
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_alloc_request,
+ TP_PROTO(struct dwc3 *dwc, struct dwc3_request *req),
+ TP_ARGS(dwc, req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_free_request,
+ TP_PROTO(struct dwc3 *dwc, struct dwc3_request *req),
+ TP_ARGS(dwc, req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_ep_queue,
+ TP_PROTO(struct dwc3 *dwc, struct dwc3_request *req),
+ TP_ARGS(dwc, req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_ep_dequeue,
+ TP_PROTO(struct dwc3 *dwc, struct dwc3_request *req),
+ TP_ARGS(dwc, req)
+);
+
+DEFINE_EVENT(dwc3_log_request, dwc3_gadget_giveback,
+ TP_PROTO(struct dwc3 *dwc, struct dwc3_request *req),
+ TP_ARGS(dwc, req)
+);
+
+#endif /* __DWC3_TRACE_H */
+
+/* this part has to be here */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>
When we're debugging hard-to-reproduce and time-sensitive use cases, printk() poses too much overhead. That's when the kernel's tracing infrastructure comes into play. This patch implements a few initial tracepoints for the dwc3 driver. More traces can be added as necessary in order to ease the task of debugging dwc3. Signed-off-by: Felipe Balbi <balbi@ti.com> --- Hi folks, I have been meaning to send this for quite a while now but never had the time to test everything and make sure it works. Logs are looking pretty good to my eyes with a much smaller overhead than with dev_* macros. If you have a real good reason to add more logs, just let me know and we will look at the possibility for adding it, I have a feeling people will want traces for endpoint 0 state machine but I'm not entirely sure it's needed, so I left it out for now. If folks think it's important, I'll add it in no time. Please give it a good review because we will have to support tracepoints for the next 60 years. cheers drivers/usb/dwc3/Makefile | 5 +- drivers/usb/dwc3/debug.c | 33 ++++++++++++ drivers/usb/dwc3/debug.h | 3 ++ drivers/usb/dwc3/ep0.c | 2 + drivers/usb/dwc3/gadget.c | 22 ++++++++ drivers/usb/dwc3/io.h | 30 +++++++++-- drivers/usb/dwc3/trace.c | 19 +++++++ drivers/usb/dwc3/trace.h | 130 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 drivers/usb/dwc3/debug.c create mode 100644 drivers/usb/dwc3/trace.c create mode 100644 drivers/usb/dwc3/trace.h