diff options
Diffstat (limited to 'drivers/usb/host/ehci-dbg.c')
| -rw-r--r-- | drivers/usb/host/ehci-dbg.c | 144 | 
1 files changed, 137 insertions, 7 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 874d2000bf9..df5546bb836 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -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;  |