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>
This commit is contained in:
Vijayavardhan Vennapusa 2013-02-14 16:33:30 +05:30 committed by David Keitel
parent 2799624a41
commit 72dfd99183
6 changed files with 547 additions and 5 deletions

View file

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

View file

@ -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 */

View file

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

View file

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

View file

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

View file

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