|
@@ -98,13 +98,18 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
|
|
|
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
|
|
|
} else {
|
|
|
ehci_dbg (ehci,
|
|
|
- "%s hcc_params %04x thresh %d uframes %s%s%s\n",
|
|
|
+ "%s hcc_params %04x thresh %d uframes %s%s%s%s%s%s%s\n",
|
|
|
label,
|
|
|
params,
|
|
|
HCC_ISOC_THRES(params),
|
|
|
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
|
|
|
HCC_CANPARK(params) ? " park" : "",
|
|
|
- HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
|
|
|
+ HCC_64BIT_ADDR(params) ? " 64 bit addr" : "",
|
|
|
+ HCC_LPM(params) ? " LPM" : "",
|
|
|
+ HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
|
|
|
+ HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
|
|
|
+ HCC_32FRAME_PERIODIC_LIST(params) ?
|
|
|
+ " 32 peridic list" : "");
|
|
|
}
|
|
|
}
|
|
|
#else
|
|
@@ -191,8 +196,9 @@ static int __maybe_unused
|
|
|
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
|
|
|
{
|
|
|
return scnprintf (buf, len,
|
|
|
- "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
|
|
|
+ "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s%s",
|
|
|
label, label [0] ? " " : "", status,
|
|
|
+ (status & STS_PPCE_MASK) ? " PPCE" : "",
|
|
|
(status & STS_ASS) ? " Async" : "",
|
|
|
(status & STS_PSS) ? " Periodic" : "",
|
|
|
(status & STS_RECL) ? " Recl" : "",
|
|
@@ -210,8 +216,9 @@ static int __maybe_unused
|
|
|
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
|
|
|
{
|
|
|
return scnprintf (buf, len,
|
|
|
- "%s%sintrenable %02x%s%s%s%s%s%s",
|
|
|
+ "%s%sintrenable %02x%s%s%s%s%s%s%s",
|
|
|
label, label [0] ? " " : "", enable,
|
|
|
+ (enable & STS_PPCE_MASK) ? " PPCE" : "",
|
|
|
(enable & STS_IAA) ? " IAA" : "",
|
|
|
(enable & STS_FATAL) ? " FATAL" : "",
|
|
|
(enable & STS_FLR) ? " FLR" : "",
|
|
@@ -228,9 +235,15 @@ static int
|
|
|
dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
|
|
|
{
|
|
|
return scnprintf (buf, len,
|
|
|
- "%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
|
|
|
+ "%s%scommand %07x %s%s%s%s%s%s=%d ithresh=%d%s%s%s%s "
|
|
|
+ "period=%s%s %s",
|
|
|
label, label [0] ? " " : "", command,
|
|
|
- (command & CMD_PARK) ? "park" : "(park)",
|
|
|
+ (command & CMD_HIRD) ? " HIRD" : "",
|
|
|
+ (command & CMD_PPCEE) ? " PPCEE" : "",
|
|
|
+ (command & CMD_FSP) ? " FSP" : "",
|
|
|
+ (command & CMD_ASPE) ? " ASPE" : "",
|
|
|
+ (command & CMD_PSPE) ? " PSPE" : "",
|
|
|
+ (command & CMD_PARK) ? " park" : "(park)",
|
|
|
CMD_PARK_CNT (command),
|
|
|
(command >> 16) & 0x3f,
|
|
|
(command & CMD_LRESET) ? " LReset" : "",
|
|
@@ -257,11 +270,22 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
|
|
|
}
|
|
|
|
|
|
return scnprintf (buf, len,
|
|
|
- "%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
|
|
|
+ "%s%sport:%d status %06x %d %s%s%s%s%s%s "
|
|
|
+ "sig=%s%s%s%s%s%s%s%s%s%s%s",
|
|
|
label, label [0] ? " " : "", port, status,
|
|
|
+ status>>25,/*device address */
|
|
|
+ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ACK ?
|
|
|
+ " ACK" : "",
|
|
|
+ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_NYET ?
|
|
|
+ " NYET" : "",
|
|
|
+ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_STALL ?
|
|
|
+ " STALL" : "",
|
|
|
+ (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ERR ?
|
|
|
+ " ERR" : "",
|
|
|
(status & PORT_POWER) ? " POWER" : "",
|
|
|
(status & PORT_OWNER) ? " OWNER" : "",
|
|
|
sig,
|
|
|
+ (status & PORT_LPM) ? " LPM" : "",
|
|
|
(status & PORT_RESET) ? " RESET" : "",
|
|
|
(status & PORT_SUSPEND) ? " SUSPEND" : "",
|
|
|
(status & PORT_RESUME) ? " RESUME" : "",
|
|
@@ -330,6 +354,13 @@ static int debug_async_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 *);
|
|
|
|
|
@@ -351,6 +382,13 @@ static const struct file_operations debug_registers_fops = {
|
|
|
.read = debug_output,
|
|
|
.release = debug_close,
|
|
|
};
|
|
|
+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,
|
|
|
+};
|
|
|
|
|
|
static struct dentry *ehci_debug_root;
|
|
|
|
|
@@ -917,6 +955,94 @@ 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;
|
|
@@ -940,6 +1066,10 @@ static inline void create_debug_files (struct ehci_hcd *ehci)
|
|
|
ehci->debug_registers = debugfs_create_file("registers", S_IRUGO,
|
|
|
ehci->debug_dir, bus,
|
|
|
&debug_registers_fops);
|
|
|
+
|
|
|
+ ehci->debug_registers = debugfs_create_file("lpm", S_IRUGO|S_IWUGO,
|
|
|
+ ehci->debug_dir, bus,
|
|
|
+ &debug_lpm_fops);
|
|
|
if (!ehci->debug_registers)
|
|
|
goto registers_error;
|
|
|
return;
|