aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/ehci-dbg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-dbg.c')
-rw-r--r--drivers/usb/host/ehci-dbg.c282
1 files changed, 135 insertions, 147 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index d6d74d2e09f..524cbf26d99 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -18,22 +18,7 @@
/* this file is part of ehci-hcd.c */
-#define ehci_dbg(ehci, fmt, args...) \
- dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-#define ehci_err(ehci, fmt, args...) \
- dev_err (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-#define ehci_info(ehci, fmt, args...) \
- dev_info (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-#define ehci_warn(ehci, fmt, args...) \
- dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-
-#ifdef VERBOSE_DEBUG
-# define ehci_vdbg ehci_dbg
-#else
- static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {}
-#endif
-
-#ifdef DEBUG
+#ifdef CONFIG_DYNAMIC_DEBUG
/* check the values in the HCSPARAMS register
* (host controller _Structural_ parameters)
@@ -77,7 +62,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
#endif
-#ifdef DEBUG
+#ifdef CONFIG_DYNAMIC_DEBUG
/* check the values in the HCCPARAMS register
* (host controller _Capability_ parameters)
@@ -107,7 +92,7 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
HCC_32FRAME_PERIODIC_LIST(params) ?
- " 32 peridic list" : "");
+ " 32 periodic list" : "");
}
}
#else
@@ -116,7 +101,7 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
#endif
-#ifdef DEBUG
+#ifdef CONFIG_DYNAMIC_DEBUG
static void __maybe_unused
dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
@@ -316,7 +301,7 @@ static inline int __maybe_unused
dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
{ return 0; }
-#endif /* DEBUG */
+#endif /* CONFIG_DYNAMIC_DEBUG */
/* functions have the "wrong" filename when they're output... */
#define dbg_status(ehci, label, status) { \
@@ -349,15 +334,9 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
/* troubleshooting help: expose state in debugfs */
static int debug_async_open(struct inode *, struct file *);
+static int debug_bandwidth_open(struct inode *, struct file *);
static int debug_periodic_open(struct inode *, struct file *);
static int debug_registers_open(struct inode *, struct file *);
-static int debug_async_open(struct inode *, struct file *);
-static int debug_lpm_open(struct inode *, struct file *);
-static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
-static ssize_t debug_lpm_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos);
-static int debug_lpm_close(struct inode *inode, struct file *file);
static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
static int debug_close(struct inode *, struct file *);
@@ -369,6 +348,13 @@ static const struct file_operations debug_async_fops = {
.release = debug_close,
.llseek = default_llseek,
};
+static const struct file_operations debug_bandwidth_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_bandwidth_open,
+ .read = debug_output,
+ .release = debug_close,
+ .llseek = default_llseek,
+};
static const struct file_operations debug_periodic_fops = {
.owner = THIS_MODULE,
.open = debug_periodic_open,
@@ -383,14 +369,6 @@ static const struct file_operations debug_registers_fops = {
.release = debug_close,
.llseek = default_llseek,
};
-static const struct file_operations debug_lpm_fops = {
- .owner = THIS_MODULE,
- .open = debug_lpm_open,
- .read = debug_lpm_read,
- .write = debug_lpm_write,
- .release = debug_lpm_close,
- .llseek = noop_llseek,
-};
static struct dentry *ehci_debug_root;
@@ -405,11 +383,11 @@ struct debug_buffer {
#define speed_char(info1) ({ char tmp; \
switch (info1 & (3 << 12)) { \
- case 0 << 12: tmp = 'f'; break; \
- case 1 << 12: tmp = 'l'; break; \
- case 2 << 12: tmp = 'h'; break; \
+ case QH_FULL_SPEED: tmp = 'f'; break; \
+ case QH_LOW_SPEED: tmp = 'l'; break; \
+ case QH_HIGH_SPEED: tmp = 'h'; break; \
default: tmp = '?'; break; \
- }; tmp; })
+ } tmp; })
static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
{
@@ -539,19 +517,105 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
spin_lock_irqsave (&ehci->lock, flags);
for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
qh_lines (ehci, qh, &next, &size);
- if (ehci->reclaim && size > 0) {
- temp = scnprintf (next, size, "\nreclaim =\n");
+ if (!list_empty(&ehci->async_unlink) && size > 0) {
+ temp = scnprintf(next, size, "\nunlink =\n");
size -= temp;
next += temp;
- for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim)
- qh_lines (ehci, qh, &next, &size);
+ list_for_each_entry(qh, &ehci->async_unlink, unlink_node) {
+ if (size <= 0)
+ break;
+ qh_lines(ehci, qh, &next, &size);
+ }
}
spin_unlock_irqrestore (&ehci->lock, flags);
return strlen(buf->output_buf);
}
+static ssize_t fill_bandwidth_buffer(struct debug_buffer *buf)
+{
+ struct ehci_hcd *ehci;
+ struct ehci_tt *tt;
+ struct ehci_per_sched *ps;
+ unsigned temp, size;
+ char *next;
+ unsigned i;
+ u8 *bw;
+ u16 *bf;
+ u8 budget[EHCI_BANDWIDTH_SIZE];
+
+ ehci = hcd_to_ehci(bus_to_hcd(buf->bus));
+ next = buf->output_buf;
+ size = buf->alloc_size;
+
+ *next = 0;
+
+ spin_lock_irq(&ehci->lock);
+
+ /* Dump the HS bandwidth table */
+ temp = scnprintf(next, size,
+ "HS bandwidth allocation (us per microframe)\n");
+ size -= temp;
+ next += temp;
+ for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) {
+ bw = &ehci->bandwidth[i];
+ temp = scnprintf(next, size,
+ "%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n",
+ i, bw[0], bw[1], bw[2], bw[3],
+ bw[4], bw[5], bw[6], bw[7]);
+ size -= temp;
+ next += temp;
+ }
+
+ /* Dump all the FS/LS tables */
+ list_for_each_entry(tt, &ehci->tt_list, tt_list) {
+ temp = scnprintf(next, size,
+ "\nTT %s port %d FS/LS bandwidth allocation (us per frame)\n",
+ dev_name(&tt->usb_tt->hub->dev),
+ tt->tt_port + !!tt->usb_tt->multi);
+ size -= temp;
+ next += temp;
+
+ bf = tt->bandwidth;
+ temp = scnprintf(next, size,
+ " %5u%5u%5u%5u%5u%5u%5u%5u\n",
+ bf[0], bf[1], bf[2], bf[3],
+ bf[4], bf[5], bf[6], bf[7]);
+ size -= temp;
+ next += temp;
+
+ temp = scnprintf(next, size,
+ "FS/LS budget (us per microframe)\n");
+ size -= temp;
+ next += temp;
+ compute_tt_budget(budget, tt);
+ for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) {
+ bw = &budget[i];
+ temp = scnprintf(next, size,
+ "%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n",
+ i, bw[0], bw[1], bw[2], bw[3],
+ bw[4], bw[5], bw[6], bw[7]);
+ size -= temp;
+ next += temp;
+ }
+ list_for_each_entry(ps, &tt->ps_list, ps_list) {
+ temp = scnprintf(next, size,
+ "%s ep %02x: %4u @ %2u.%u+%u mask %04x\n",
+ dev_name(&ps->udev->dev),
+ ps->ep->desc.bEndpointAddress,
+ ps->tt_usecs,
+ ps->bw_phase, ps->phase_uf,
+ ps->bw_period, ps->cs_mask);
+ size -= temp;
+ next += temp;
+ }
+ }
+ spin_unlock_irq(&ehci->lock);
+
+ return next - buf->output_buf;
+}
+
#define DBG_SCHED_LIMIT 64
static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
{
@@ -598,7 +662,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
case Q_TYPE_QH:
hw = p.qh->hw;
temp = scnprintf (next, size, " qh%d-%04x/%p",
- p.qh->period,
+ p.qh->ps.period,
hc32_to_cpup(ehci,
&hw->hw_info2)
/* uframe masks */
@@ -645,7 +709,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
speed_char (scratch),
scratch & 0x007f,
(scratch >> 8) & 0x000f, type,
- p.qh->usecs, p.qh->c_usecs,
+ p.qh->ps.usecs,
+ p.qh->ps.c_usecs,
temp,
0x7ff & (scratch >> 16));
@@ -653,10 +718,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
seen [seen_count++].qh = p.qh;
} else
temp = 0;
- if (p.qh) {
- tag = Q_NEXT_TYPE(ehci, hw->hw_next);
- p = p.qh->qh_next;
- }
+ tag = Q_NEXT_TYPE(ehci, hw->hw_next);
+ p = p.qh->qh_next;
break;
case Q_TYPE_FSTN:
temp = scnprintf (next, size,
@@ -674,7 +737,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
case Q_TYPE_SITD:
temp = scnprintf (next, size,
" sitd%d-%04x/%p",
- p.sitd->stream->interval,
+ p.sitd->stream->ps.period,
hc32_to_cpup(ehci, &p.sitd->hw_uframe)
& 0x0000ffff,
p.sitd);
@@ -706,6 +769,8 @@ static const char *rh_state_string(struct ehci_hcd *ehci)
return "suspended";
case EHCI_RH_RUNNING:
return "running";
+ case EHCI_RH_STOPPING:
+ return "stopping";
}
return "?";
}
@@ -753,7 +818,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
#ifdef CONFIG_PCI
/* EHCI 0.96 and later may have "extended capabilities" */
- if (hcd->self.controller->bus == &pci_bus_type) {
+ if (dev_is_pci(hcd->self.controller)) {
struct pci_dev *pdev;
u32 offset, cap, cap2;
unsigned count = 256/4;
@@ -842,16 +907,18 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
}
}
- if (ehci->reclaim) {
- temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
+ if (!list_empty(&ehci->async_unlink)) {
+ temp = scnprintf(next, size, "async unlink qh %p\n",
+ list_first_entry(&ehci->async_unlink,
+ struct ehci_qh, unlink_node));
size -= temp;
next += temp;
}
#ifdef EHCI_STATS
temp = scnprintf (next, size,
- "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
- ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+ "irq normal %ld err %ld iaa %ld (lost %ld)\n",
+ ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
ehci->stats.lost_iaa);
size -= temp;
next += temp;
@@ -943,6 +1010,7 @@ static int debug_close(struct inode *inode, struct file *file)
return 0;
}
+
static int debug_async_open(struct inode *inode, struct file *file)
{
file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
@@ -950,6 +1018,14 @@ static int debug_async_open(struct inode *inode, struct file *file)
return file->private_data ? 0 : -ENOMEM;
}
+static int debug_bandwidth_open(struct inode *inode, struct file *file)
+{
+ file->private_data = alloc_buffer(inode->i_private,
+ fill_bandwidth_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
static int debug_periodic_open(struct inode *inode, struct file *file)
{
struct debug_buffer *buf;
@@ -970,94 +1046,6 @@ static int debug_registers_open(struct inode *inode, struct file *file)
return file->private_data ? 0 : -ENOMEM;
}
-static int debug_lpm_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static int debug_lpm_close(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- /* TODO: show lpm stats */
- return 0;
-}
-
-static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
- char buf[50];
- size_t len;
- u32 temp;
- unsigned long port;
- u32 __iomem *portsc ;
- u32 params;
-
- hcd = bus_to_hcd(file->private_data);
- ehci = hcd_to_ehci(hcd);
-
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
- if (len > 0 && buf[len - 1] == '\n')
- buf[len - 1] = '\0';
-
- if (strncmp(buf, "enable", 5) == 0) {
- if (strict_strtoul(buf + 7, 10, &port))
- return -EINVAL;
- params = ehci_readl(ehci, &ehci->caps->hcs_params);
- if (port > HCS_N_PORTS(params)) {
- ehci_dbg(ehci, "ERR: LPM on bad port %lu\n", port);
- return -ENODEV;
- }
- portsc = &ehci->regs->port_status[port-1];
- temp = ehci_readl(ehci, portsc);
- if (!(temp & PORT_DEV_ADDR)) {
- ehci_dbg(ehci, "LPM: no device attached\n");
- return -ENODEV;
- }
- temp |= PORT_LPM;
- ehci_writel(ehci, temp, portsc);
- printk(KERN_INFO "force enable LPM for port %lu\n", port);
- } else if (strncmp(buf, "hird=", 5) == 0) {
- unsigned long hird;
- if (strict_strtoul(buf + 5, 16, &hird))
- return -EINVAL;
- printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird);
- temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~CMD_HIRD;
- temp |= hird << 24;
- ehci_writel(ehci, temp, &ehci->regs->command);
- } else if (strncmp(buf, "disable", 7) == 0) {
- if (strict_strtoul(buf + 8, 10, &port))
- return -EINVAL;
- params = ehci_readl(ehci, &ehci->caps->hcs_params);
- if (port > HCS_N_PORTS(params)) {
- ehci_dbg(ehci, "ERR: LPM off bad port %lu\n", port);
- return -ENODEV;
- }
- portsc = &ehci->regs->port_status[port-1];
- temp = ehci_readl(ehci, portsc);
- if (!(temp & PORT_DEV_ADDR)) {
- ehci_dbg(ehci, "ERR: no device attached\n");
- return -ENODEV;
- }
- temp &= ~PORT_LPM;
- ehci_writel(ehci, temp, portsc);
- printk(KERN_INFO "disabled LPM for port %lu\n", port);
- } else
- return -EOPNOTSUPP;
- return count;
-}
-
static inline void create_debug_files (struct ehci_hcd *ehci)
{
struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
@@ -1070,6 +1058,10 @@ static inline void create_debug_files (struct ehci_hcd *ehci)
&debug_async_fops))
goto file_error;
+ if (!debugfs_create_file("bandwidth", S_IRUGO, ehci->debug_dir, bus,
+ &debug_bandwidth_fops))
+ goto file_error;
+
if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,
&debug_periodic_fops))
goto file_error;
@@ -1078,10 +1070,6 @@ static inline void create_debug_files (struct ehci_hcd *ehci)
&debug_registers_fops))
goto file_error;
- if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus,
- &debug_lpm_fops))
- goto file_error;
-
return;
file_error: