From: Lu Baolu <baolu.lu@linux.intel.com>
To: Mathias Nyman <mathias.nyman@intel.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Alan Stern <stern@rowland.harvard.edu>
Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
Lu Baolu <baolu.lu@linux.intel.com>
Subject: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Date: Wed, 28 Oct 2015 16:00:32 +0800 [thread overview]
Message-ID: <1446019243-5565-2-git-send-email-baolu.lu@linux.intel.com> (raw)
In-Reply-To: <1446019243-5565-1-git-send-email-baolu.lu@linux.intel.com>
The xHCI host exports xHCI-specific extended capabilities utilizing
a method similar to PCI extended capabilities. In many cases, users
want to know whether a specific extended capability is supported by
a host. Unfortunately, currently there's no existing mechanisms in
the kernel to do this.
This patch exposes extended capabilities supported by the xHCI host
via debugfs.
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
drivers/usb/host/xhci-dbg.c | 212 +++++++++++++++++++++++++++++++++++++++
drivers/usb/host/xhci-ext-caps.h | 9 +-
drivers/usb/host/xhci.c | 27 ++++-
drivers/usb/host/xhci.h | 10 ++
4 files changed, 256 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 74c42f7..d3dcfed 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -20,6 +20,11 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/usb.h>
+
#include "xhci.h"
#define XHCI_INIT_VALUE 0x0
@@ -612,3 +617,210 @@ void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
va_end(args);
}
EXPORT_SYMBOL_GPL(xhci_dbg_trace);
+
+#ifdef CONFIG_DEBUG_FS
+struct debug_buffer {
+ ssize_t (*fill_func)(struct debug_buffer *);
+ struct usb_bus *bus;
+ struct mutex mutex;
+ size_t count;
+ char *output_buf;
+ size_t alloc_size;
+};
+
+static const char *get_extcap_desc(u32 cap_id)
+{
+ switch (cap_id) {
+ case XHCI_EXT_CAPS_LEGACY:
+ return "USB Legacy Support";
+ case XHCI_EXT_CAPS_PROTOCOL:
+ return "Supported Protocol";
+ case XHCI_EXT_CAPS_PM:
+ return "Extended Power Management";
+ case XHCI_EXT_CAPS_VIRT:
+ return "I/O Virtualization (xHCI-IOV)";
+ case XHCI_EXT_CAPS_ROUTE:
+ return "Message Interrupt";
+ case XHCI_EXT_CAPS_LOCALMEM:
+ return "Local Memory";
+ case XHCI_EXT_CAPS_DEBUG:
+ return "USB Debug Capability";
+ default:
+ if (XHCI_EXT_CAPS_VENDOR(XHCI_EXT_CAPS_ID(cap_id)))
+ return "Vendor Defined";
+ else
+ return "Unknown";
+ }
+}
+
+static ssize_t fill_extcap_buffer(struct debug_buffer *buf)
+{
+ __le32 __iomem *addr;
+ struct usb_hcd *hcd;
+ struct xhci_hcd *xhci;
+ u32 offset, cap_id;
+ char *next;
+ int size, temp;
+ unsigned long flags;
+ int time_to_leave;
+
+ hcd = bus_to_hcd(buf->bus);
+ xhci = hcd_to_xhci(hcd);
+ next = buf->output_buf;
+ size = buf->alloc_size;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ addr = &xhci->cap_regs->hcc_params;
+ offset = XHCI_HCC_EXT_CAPS(readl(addr));
+ if (!HCD_HW_ACCESSIBLE(hcd) || !offset) {
+ size = scnprintf(next, size,
+ "bus %s, device %s\n%s\nNo extended capabilities\n",
+ hcd->self.controller->bus->name,
+ dev_name(hcd->self.controller),
+ hcd->product_desc);
+ goto done;
+ }
+
+ temp = scnprintf(next, size, "@addr(virt)\t\tCAP_ID\tDescription\n");
+ size -= temp;
+ next += temp;
+
+ addr = &xhci->cap_regs->hc_capbase + offset;
+ time_to_leave = XHCI_EXT_MAX_CAPID;
+ while (time_to_leave--) {
+ cap_id = readl(addr);
+ temp = scnprintf(next, size, "@%p\t%02x\t%s\n",
+ addr, XHCI_EXT_CAPS_ID(cap_id),
+ get_extcap_desc(XHCI_EXT_CAPS_ID(cap_id)));
+ size -= temp;
+ next += temp;
+
+ offset = XHCI_EXT_CAPS_NEXT(cap_id);
+ if (!offset)
+ break;
+ addr += offset;
+ }
+
+done:
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ return buf->alloc_size - size;
+}
+
+static struct debug_buffer *buffer_init(struct usb_bus *bus,
+ ssize_t (*fill_func)(struct debug_buffer *))
+{
+ struct debug_buffer *buf;
+
+ buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ buf->bus = bus;
+ buf->fill_func = fill_func;
+ mutex_init(&buf->mutex);
+
+ return buf;
+}
+
+static int fill_buffer(struct debug_buffer *buf)
+{
+ int ret;
+
+ if (buf->output_buf)
+ return -EINVAL;
+
+ buf->alloc_size = PAGE_SIZE;
+ buf->output_buf = vmalloc(buf->alloc_size);
+
+ if (!buf->output_buf)
+ return -ENOMEM;
+
+ ret = buf->fill_func(buf);
+ if (ret < 0)
+ return ret;
+
+ buf->count = ret;
+
+ return 0;
+}
+
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+ size_t len, loff_t *offset)
+{
+ struct debug_buffer *buf = file->private_data;
+ int ret = 0;
+
+ mutex_lock(&buf->mutex);
+ if (!buf->count) {
+ ret = fill_buffer(buf);
+ if (ret) {
+ mutex_unlock(&buf->mutex);
+ return ret;
+ }
+ }
+ mutex_unlock(&buf->mutex);
+
+ return simple_read_from_buffer(user_buf, len, offset,
+ buf->output_buf, buf->count);
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ struct debug_buffer *buf = file->private_data;
+
+ if (buf) {
+ vfree(buf->output_buf);
+ kfree(buf);
+ }
+
+ return 0;
+}
+
+static int debug_extcap_open(struct inode *inode, struct file *file)
+{
+ file->private_data = buffer_init(inode->i_private,
+ fill_extcap_buffer);
+
+ return file->private_data ? 0 : -ENOMEM;
+}
+
+static const struct file_operations debug_extcap_fops = {
+ .owner = THIS_MODULE,
+ .open = debug_extcap_open,
+ .read = debug_output,
+ .release = debug_close,
+ .llseek = default_llseek,
+};
+
+struct dentry *xhci_debug_root;
+
+void xhci_create_debug_files(struct xhci_hcd *xhci)
+{
+ struct usb_bus *bus = &xhci_to_hcd(xhci)->self;
+ struct dentry *entry;
+
+ if (!xhci_debug_root)
+ return;
+
+ entry = debugfs_create_dir(bus->bus_name, xhci_debug_root);
+ if (!entry || IS_ERR(entry)) {
+ xhci_info(xhci, "failed to create debug dir");
+ return;
+ }
+ xhci->debug_dir = entry;
+
+ if (!debugfs_create_file("extcap", S_IRUGO,
+ xhci->debug_dir, bus,
+ &debug_extcap_fops))
+ xhci_info(xhci, "failed to create extcap debug file");
+}
+
+void xhci_remove_debug_files(struct xhci_hcd *xhci)
+{
+ debugfs_remove_recursive(xhci->debug_dir);
+ xhci->debug_dir = NULL;
+}
+
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 9fe3225..e233c90 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -49,8 +49,15 @@
#define XHCI_EXT_CAPS_PM 3
#define XHCI_EXT_CAPS_VIRT 4
#define XHCI_EXT_CAPS_ROUTE 5
-/* IDs 6-9 reserved */
+#define XHCI_EXT_CAPS_LOCALMEM 6
+/* IDs 7-9 reserved */
#define XHCI_EXT_CAPS_DEBUG 10
+/* IDs 192-255 vendor specific */
+#define XHCI_EXT_CAPS_VEN_START 192
+#define XHCI_EXT_CAPS_VEN_END 255
+#define XHCI_EXT_CAPS_VENDOR(p) (((p) >= XHCI_EXT_CAPS_VEN_START) && \
+ ((p) <= XHCI_EXT_CAPS_VEN_END))
+#define XHCI_EXT_MAX_CAPID XHCI_EXT_CAPS_VEN_END
/* USB Legacy Support Capability - section 7.1.1 */
#define XHCI_HC_BIOS_OWNED (1 << 16)
#define XHCI_HC_OS_OWNED (1 << 24)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6e7dc6f..ddcb4b7 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
#include "xhci.h"
#include "xhci-trace.h"
@@ -651,6 +652,11 @@ int xhci_run(struct usb_hcd *hcd)
}
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Finished xhci_run for USB2 roothub");
+
+#ifdef CONFIG_DEBUG_FS
+ xhci_create_debug_files(xhci);
+#endif
+
return 0;
}
EXPORT_SYMBOL_GPL(xhci_run);
@@ -669,6 +675,10 @@ void xhci_stop(struct usb_hcd *hcd)
u32 temp;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+#ifdef CONFIG_DEBUG_FS
+ xhci_remove_debug_files(xhci);
+#endif
+
if (xhci->xhc_state & XHCI_STATE_HALTED)
return;
@@ -5041,6 +5051,15 @@ static int __init xhci_hcd_init(void)
BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
+
+#ifdef CONFIG_DEBUG_FS
+ xhci_debug_root = debugfs_create_dir("xhci", usb_debug_root);
+ if (!xhci_debug_root || IS_ERR(xhci_debug_root)) {
+ debugfs_remove(xhci_debug_root);
+ xhci_debug_root = NULL;
+ }
+#endif
+
return 0;
}
@@ -5048,7 +5067,13 @@ static int __init xhci_hcd_init(void)
* If an init function is provided, an exit function must also be provided
* to allow module unload.
*/
-static void __exit xhci_hcd_fini(void) { }
+static void __exit xhci_hcd_fini(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(xhci_debug_root);
+ xhci_debug_root = NULL;
+#endif
+}
module_init(xhci_hcd_init);
module_exit(xhci_hcd_fini);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index be9048e..dc3a5f8 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1657,6 +1657,10 @@ struct xhci_hcd {
u32 port_status_u0;
/* Compliance Mode Timer Triggered every 2 seconds */
#define COMP_MODE_RCVRY_MSECS 2000
+ /* debug files */
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debug_dir;
+#endif /* CONFIG_DEBUG_FS */
};
/* Platform specific overrides to generic XHCI hc_driver ops */
@@ -1743,6 +1747,12 @@ void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
const char *fmt, ...);
+#ifdef CONFIG_DEBUG_FS
+extern struct dentry *xhci_debug_root;
+void xhci_create_debug_files(struct xhci_hcd *xhci);
+void xhci_remove_debug_files(struct xhci_hcd *xhci);
+#endif /* CONFIG_DEBUG_FS */
+
/* xHCI memory management */
void xhci_mem_cleanup(struct xhci_hcd *xhci);
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags);
--
2.1.4
next prev parent reply other threads:[~2015-10-28 8:00 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-10-28 8:00 [PATCH 00/12] usb: early: add support for early printk through USB3 debug port Lu Baolu
2015-10-28 8:00 ` Lu Baolu [this message]
2015-10-28 9:27 ` [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs Oliver Neukum
2015-10-29 1:18 ` Lu, Baolu
2015-10-28 12:40 ` Greg Kroah-Hartman
2015-10-29 1:22 ` Lu, Baolu
2015-10-30 12:09 ` Lu, Baolu
2015-10-30 14:45 ` Greg Kroah-Hartman
2015-11-02 13:07 ` Lu, Baolu
2015-10-28 8:00 ` [PATCH 02/12] x86: fixmap: add permanent fixmap for xhci debug port Lu Baolu
2015-10-28 8:00 ` [PATCH 03/12] usb: xhci: dbc: probe and setup xhci debug capability Lu Baolu
2015-10-28 8:00 ` [PATCH 04/12] usb: xhci: dbc: add support for Intel xHCI dbc quirk Lu Baolu
2015-10-28 8:00 ` [PATCH 05/12] usb: xhci: dbc: add debug buffer Lu Baolu
2015-10-28 8:00 ` [PATCH 06/12] usb: xhci: dbc: add bulk out and bulk in interfaces Lu Baolu
2015-10-28 8:00 ` [PATCH 07/12] usb: xhci: dbc: handle dbc-configured exit Lu Baolu
2015-10-28 8:00 ` [PATCH 08/12] usb: xhci: dbc: handle endpoint stall Lu Baolu
2015-10-28 8:00 ` [PATCH 09/12] x86: early_printk: add USB3 debug port earlyprintk support Lu Baolu
2015-10-28 8:00 ` [PATCH 10/12] usb: xhci: dbc: add handshake between debug target and host Lu Baolu
2015-10-28 8:00 ` [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device Lu Baolu
2015-10-28 9:10 ` Johan Hovold
2015-10-29 1:24 ` Lu, Baolu
2015-10-28 12:33 ` Greg Kroah-Hartman
2015-10-29 1:43 ` Lu, Baolu
2015-10-30 11:46 ` Lu, Baolu
2015-10-30 14:41 ` Greg Kroah-Hartman
2015-10-31 5:37 ` Lu, Baolu
2015-10-28 8:00 ` [PATCH 12/12] usb: doc: add document for xHCI DbC driver Lu Baolu
2015-11-03 9:42 ` [PATCH 00/12] usb: early: add support for early printk through USB3 debug port Dave Young
2015-11-04 0:40 ` Lu, Baolu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1446019243-5565-2-git-send-email-baolu.lu@linux.intel.com \
--to=baolu.lu@linux.intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mathias.nyman@intel.com \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.