From 65475023928bce90a98aa4e44047fd17afead050 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 21 May 2018 16:40:05 +0300 Subject: xhci: debugfs: add usb ports to xhci debugfs Add ports/portxx/portsc for each xHC hardware usb port to debugfs. Showing the content of the port status and control register for each port (PORTSC) Portxx is numbered starting from 1 for historical reasons to better match port numbering shown by lsusb and other places. Ports in debugfs are in the order XHC controller has them, In most cases USB2 ports come first, followed by USB3 ports. i.e. USB2 ports are port01-portxx, and USB3 portxx-portmax. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-debugfs.c | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/usb/host/xhci-debugfs.c') diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 5851052d4668..76e446a889bd 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -333,6 +333,31 @@ static const struct file_operations xhci_context_fops = { .release = single_release, }; + + +static int xhci_portsc_show(struct seq_file *s, void *unused) +{ + struct xhci_port *port = s->private; + u32 portsc; + + portsc = readl(port->addr); + seq_printf(s, "%s\n", xhci_decode_portsc(portsc)); + + return 0; +} + +static int xhci_port_open(struct inode *inode, struct file *file) +{ + return single_open(file, xhci_portsc_show, inode->i_private); +} + +static const struct file_operations port_fops = { + .open = xhci_port_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void xhci_debugfs_create_files(struct xhci_hcd *xhci, struct xhci_file_map *files, size_t nentries, void *data, @@ -449,6 +474,27 @@ void xhci_debugfs_remove_slot(struct xhci_hcd *xhci, int slot_id) dev->debugfs_private = NULL; } +static void xhci_debugfs_create_ports(struct xhci_hcd *xhci, + struct dentry *parent) +{ + unsigned int num_ports; + char port_name[8]; + struct xhci_port *port; + struct dentry *dir; + + num_ports = HCS_MAX_PORTS(xhci->hcs_params1); + + parent = debugfs_create_dir("ports", parent); + + while (num_ports--) { + scnprintf(port_name, sizeof(port_name), "port%02d", + num_ports + 1); + dir = debugfs_create_dir(port_name, parent); + port = &xhci->hw_ports[num_ports]; + debugfs_create_file("portsc", 0444, dir, port, &port_fops); + } +} + void xhci_debugfs_init(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.controller; @@ -497,6 +543,8 @@ void xhci_debugfs_init(struct xhci_hcd *xhci) xhci->debugfs_root); xhci->debugfs_slots = debugfs_create_dir("devices", xhci->debugfs_root); + + xhci_debugfs_create_ports(xhci, xhci->debugfs_root); } void xhci_debugfs_exit(struct xhci_hcd *xhci) -- cgit v1.2.3 From 87a03802184c866af35a8fcdd5fd14d94e9bf9eb Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 21 May 2018 16:40:06 +0300 Subject: xhci: debugfs: add debugfs interface to enable compliance mode for a port Enable compliance transition for a port by writing "compliance" to the ports portsc file in debugfs. port must be "Not-connected" and Link must be in RxDetect state to enable compliance mode. Only needed for host that have CTC flag set. Allows state transitioning to compliance at 1st LFPS timeout. Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-debugfs.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers/usb/host/xhci-debugfs.c') diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 76e446a889bd..cadc01336bf8 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -8,6 +8,7 @@ */ #include +#include #include "xhci.h" #include "xhci-debugfs.h" @@ -351,8 +352,44 @@ static int xhci_port_open(struct inode *inode, struct file *file) return single_open(file, xhci_portsc_show, inode->i_private); } +static ssize_t xhci_port_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct xhci_port *port = s->private; + struct xhci_hcd *xhci = hcd_to_xhci(port->rhub->hcd); + char buf[32]; + u32 portsc; + unsigned long flags; + + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (!strncmp(buf, "compliance", 10)) { + /* If CTC is clear, compliance is enabled by default */ + if (!HCC2_CTC(xhci->hcc_params2)) + return count; + spin_lock_irqsave(&xhci->lock, flags); + /* compliance mode can only be enabled on ports in RxDetect */ + portsc = readl(port->addr); + if ((portsc & PORT_PLS_MASK) != XDEV_RXDETECT) { + spin_unlock_irqrestore(&xhci->lock, flags); + return -EPERM; + } + portsc = xhci_port_state_to_neutral(portsc); + portsc &= ~PORT_PLS_MASK; + portsc |= PORT_LINK_STROBE | XDEV_COMP_MODE; + writel(portsc, port->addr); + spin_unlock_irqrestore(&xhci->lock, flags); + } else { + return -EINVAL; + } + return count; +} + static const struct file_operations port_fops = { .open = xhci_port_open, + .write = xhci_port_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, @@ -491,7 +528,7 @@ static void xhci_debugfs_create_ports(struct xhci_hcd *xhci, num_ports + 1); dir = debugfs_create_dir(port_name, parent); port = &xhci->hw_ports[num_ports]; - debugfs_create_file("portsc", 0444, dir, port, &port_fops); + debugfs_create_file("portsc", 0644, dir, port, &port_fops); } } -- cgit v1.2.3