Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1257761 > unrolled thread

[PATCH 00/12] usb: early: add support for early printk through USB3 debug port

Started byLu Baolu <baolu.lu@linux.intel.com>
First post2015-10-28 09:10 +0100
Last post2015-10-28 09:10 +0100
Articles 19 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 00/12] usb: early: add support for early printk through USB3 debug port Lu Baolu <baolu.lu@linux.intel.com> - 2015-10-28 09:10 +0100
    [PATCH 07/12] usb: xhci: dbc: handle dbc-configured exit Lu Baolu <baolu.lu@linux.intel.com> - 2015-10-28 09:10 +0100
    [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs Lu Baolu <baolu.lu@linux.intel.com> - 2015-10-28 09:10 +0100
      Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via  debugfs Oliver Neukum <oneukum@suse.com> - 2015-10-28 10:30 +0100
        Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via  debugfs "Lu, Baolu" <baolu.lu@linux.intel.com> - 2015-10-29 02:20 +0100
      Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via  debugfs Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2015-10-28 13:50 +0100
        Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via  debugfs "Lu, Baolu" <baolu.lu@linux.intel.com> - 2015-10-29 02:30 +0100
        Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via  debugfs "Lu, Baolu" <baolu.lu@linux.intel.com> - 2015-10-30 13:10 +0100
          Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via  debugfs Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2015-10-30 15:50 +0100
    [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device Lu Baolu <baolu.lu@linux.intel.com> - 2015-10-28 09:10 +0100
      Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug  device Johan Hovold <johan@kernel.org> - 2015-10-28 10:20 +0100
        Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug  device "Lu, Baolu" <baolu.lu@linux.intel.com> - 2015-10-29 02:30 +0100
      Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug  device Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2015-10-28 13:40 +0100
        Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug  device "Lu, Baolu" <baolu.lu@linux.intel.com> - 2015-10-29 02:50 +0100
        Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug  device "Lu, Baolu" <baolu.lu@linux.intel.com> - 2015-10-30 12:50 +0100
          Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug  device Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2015-10-30 15:50 +0100
            Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug  device "Lu, Baolu" <baolu.lu@linux.intel.com> - 2015-10-31 06:40 +0100
    [PATCH 06/12] usb: xhci: dbc: add bulk out and bulk in interfaces Lu Baolu <baolu.lu@linux.intel.com> - 2015-10-28 09:10 +0100
    [PATCH 03/12] usb: xhci: dbc: probe and setup xhci debug capability Lu Baolu <baolu.lu@linux.intel.com> - 2015-10-28 09:10 +0100

#1257761 — [PATCH 00/12] usb: early: add support for early printk through USB3 debug port

FromLu Baolu <baolu.lu@linux.intel.com>
Date2015-10-28 09:10 +0100
Subject[PATCH 00/12] usb: early: add support for early printk through USB3 debug port
Message-ID<qotXY-8vm-19@gated-at.bofh.it>
This patch series adds support for early printk through USB3 debug port.
USB3 debug port is described in xHCI specification as an optional extended
capability.

The first patch adds a file in debugfs, through which users can check
whether the debug capability is supported by a specific host controller.

Patch 2 to 10 add the driver for xHCI debug capability. It interfaces with
the register set and provides the required ops (read/write/control) to upper
layers. Early printk is one consumer of these ops. The hooks for early printk
are introduced in patch 9. This design is similar to what we have done in
drivers/usb/early/ehci-dbgp.c.

Patch 11 is a minor change to usb_debug module. This change is required to
bind usb_debug with the USB3 debug device.

Patch 12 is the design document and user guide.

Lu Baolu (12):
  usb: xhci: expose xhci extended capabilities via debugfs
  x86: fixmap: add permanent fixmap for xhci debug port
  usb: xhci: dbc: probe and setup xhci debug capability
  usb: xhci: dbc: add support for Intel xHCI dbc quirk
  usb: xhci: dbc: add debug buffer
  usb: xhci: dbc: add bulk out and bulk in interfaces
  usb: xhci: dbc: handle dbc-configured exit
  usb: xhci: dbc: handle endpoint stall
  x86: early_printk: add USB3 debug port earlyprintk support
  usb: xhci: dbc: add handshake between debug target and host
  usb: serial: usb_debug: add support for dbc debug device
  usb: doc: add document for xHCI DbC driver

 Documentation/kernel-parameters.txt |    1 +
 Documentation/usb/xhci-dbc.txt      |  325 ++++++++
 MAINTAINERS                         |    8 +
 arch/x86/Kconfig.debug              |   12 +
 arch/x86/include/asm/fixmap.h       |    4 +
 arch/x86/kernel/early_printk.c      |    5 +
 drivers/usb/early/Makefile          |    1 +
 drivers/usb/early/xhci-dbc.c        | 1407 +++++++++++++++++++++++++++++++++++
 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 +
 drivers/usb/serial/usb_debug.c      |   29 +-
 include/linux/usb/xhci-dbc.h        |  224 ++++++
 14 files changed, 2269 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/usb/xhci-dbc.txt
 create mode 100644 drivers/usb/early/xhci-dbc.c
 create mode 100644 include/linux/usb/xhci-dbc.h

-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1257763 — [PATCH 07/12] usb: xhci: dbc: handle dbc-configured exit

FromLu Baolu <baolu.lu@linux.intel.com>
Date2015-10-28 09:10 +0100
Subject[PATCH 07/12] usb: xhci: dbc: handle dbc-configured exit
Message-ID<qotXZ-8vm-47@gated-at.bofh.it>
In reply to#1257761
DbC might exit configured state in some cases (refer to 7.6.4.4 in
xHCI spec 1.1). Software needs detect and clear this situation by
clearing DCCTRL.DCR and wait until the DbC configured before read
or write oprations.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/usb/early/xhci-dbc.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index f51daa4..8a5a51f 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -1153,6 +1153,29 @@ static int xdbc_wait_until_bulk_done(struct xdbc_trb *trb, int loops)
 	return -EIO;
 }
 
+static int xdbc_wait_until_dbc_configured(void)
+{
+	int timeout = 0;
+	u32 reg;
+
+	/* Port exits configured state */
+	reg = readl(&xdbcp->xdbc_reg->control);
+	if (!(reg & CTRL_DRC))
+		return 0;
+
+	/* clear run change bit (RW1C) */
+	writel(reg | CTRL_DRC, &xdbcp->xdbc_reg->control);
+
+	do {
+		if (readl(&xdbcp->xdbc_reg->control) & CTRL_DCR)
+			return 0;
+
+		xdbc_udelay(10);
+	} while (timeout++ < XDBC_LOOPS);
+
+	return -ETIMEDOUT;
+}
+
 static int xdbc_bulk_transfer(void *data, int size, int loops, bool read)
 {
 	u64 addr;
@@ -1167,6 +1190,11 @@ static int xdbc_bulk_transfer(void *data, int size, int loops, bool read)
 		return -EINVAL;
 	}
 
+	if (xdbc_wait_until_dbc_configured()) {
+		xdbc_trace("%s: hardware not ready\n", __func__);
+		return -EPERM;
+	}
+
 	ring = (read ? &xdbcp->in_ring : &xdbcp->out_ring);
 	trb = ring->enqueue;
 	cycle = ring->cycle_state;
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257764 — [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

FromLu Baolu <baolu.lu@linux.intel.com>
Date2015-10-28 09:10 +0100
Subject[PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Message-ID<qotXZ-8vm-39@gated-at.bofh.it>
In reply to#1257761
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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257848 — Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

FromOliver Neukum <oneukum@suse.com>
Date2015-10-28 10:30 +0100
SubjectRe: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Message-ID<qovdo-Lu-13@gated-at.bofh.it>
In reply to#1257764
On Wed, 2015-10-28 at 16:00 +0800, Lu Baolu wrote:
> 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);

That really makes no sense. If you allocate exactly
PAGE_SIZE, you should allocate a page.

	Regards
		Oliver


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1258507 — Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

From"Lu, Baolu" <baolu.lu@linux.intel.com>
Date2015-10-29 02:20 +0100
SubjectRe: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Message-ID<qoK2K-1XL-3@gated-at.bofh.it>
In reply to#1257848

On 10/28/2015 05:27 PM, Oliver Neukum wrote:
>> +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);
> That really makes no sense. If you allocate exactly
> PAGE_SIZE, you should allocate a page.

Yes, I will change it in v2.

>
> 	Regards
> 		Oliver

Thanks,
Baolu

>
>
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257955 — Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

FromGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Date2015-10-28 13:50 +0100
SubjectRe: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Message-ID<qoykW-2Fh-3@gated-at.bofh.it>
In reply to#1257764
On Wed, Oct 28, 2015 at 04:00:32PM +0800, Lu Baolu wrote:
> 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.

Why not through sysfs so that all users can see them?  Why debugfs,
which really is only for "debugging"?


> 
> 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

You shouldn't ever need to #ifdef your code for CONFIG_DEBUG_FS, the
functions work the same if it's enabled or not.

> +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";

This is a lot more stuff than just debug port, it should be in sysfs
as individual files, not one big one that you somehow have to parse in
order to determine this information.

> +	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");

Why are "errors" an info level?

> +		return;

No, you just "failed" if debugfs is not enabled.

You don't need to do any real error checking here, just make the call
and save off the dentry.  If an error happened, it's NULL and you can't
really do anything with that, and it's safe to pass back into debugfs
for other things, so you are fine.  Don't make debugfs interactions more
complex than they have to be.


> +	}
> +	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");

Again, info level?

> +}
> +
> +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

Don't ever put ifdefs in .c code if you can prevent it.  Hint, you can
prevent it here...

> +
>  	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

Same here.

> +
>  	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

And same here.

> +
>  	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

And here.


> +}
>  
>  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 */

No need for ifdef here as well.

>  };
>  
>  /* 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 */

Or here like this...

But as you are moving this to sysfs, it's kind of moot...

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1258514 — Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

From"Lu, Baolu" <baolu.lu@linux.intel.com>
Date2015-10-29 02:30 +0100
SubjectRe: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Message-ID<qoKcq-21b-1@gated-at.bofh.it>
In reply to#1257955

On 10/28/2015 08:40 PM, Greg Kroah-Hartman wrote:
>> >+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";
> This is a lot more stuff than just debug port, it should be in sysfs
> as individual files, not one big one that you somehow have to parse in
> order to determine this information.
>

I will move it into sysfs in v2.

Thanks,
Baolu
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1259440 — Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

From"Lu, Baolu" <baolu.lu@linux.intel.com>
Date2015-10-30 13:10 +0100
SubjectRe: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Message-ID<qpgFj-5Eg-1@gated-at.bofh.it>
In reply to#1257955

On 10/28/2015 08:40 PM, Greg Kroah-Hartman wrote:
>> +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";
> This is a lot more stuff than just debug port, it should be in sysfs
> as individual files, not one big one that you somehow have to parse in
> order to determine this information.
>

Hi Greg,

It's hard to put each extended capability into a individual sysfs file.

The extended capabilities are optional. One extended capability
might be supported in one hardware, but not in another. Also,
there are many "vendor defined" capabilities (ID range 192-255).
The vendor defined capabilities are not defined in xhci spec and
they could be used by the hardware vendor for various purposes.

The purpose of this patch is to let user know what kind of extended
capabilities does a host controller supported. For example, on
one of my develop machines, it prints,

@addr(virt)        CAP_ID    Description
@ffffc90001c88000    02    Supported Protocol
@ffffc90001c88020    02    Supported Protocol
@ffffc90001c88070    c0    Vendor Defined
@ffffc90001c8846c    01    USB Legacy Support
@ffffc90001c884f4    c6    Vendor Defined
@ffffc90001c88500    c7    Vendor Defined
@ffffc90001c88600    c2    Vendor Defined
@ffffc90001c88700    0a    USB Debug Capability
@ffffc90001c88740    c3    Vendor Defined
@ffffc90001c88800    c4    Vendor Defined
@ffffc90001c88900    c5    Vendor Defined

With this output I know that "USB Debug Capability" is supported
in my machine.

Thanks,
Baolu
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1259559 — Re: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs

FromGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Date2015-10-30 15:50 +0100
SubjectRe: [PATCH 01/12] usb: xhci: expose xhci extended capabilities via debugfs
Message-ID<qpjaa-70R-13@gated-at.bofh.it>
In reply to#1259440
On Fri, Oct 30, 2015 at 08:09:17PM +0800, Lu, Baolu wrote:
> 
> 
> On 10/28/2015 08:40 PM, Greg Kroah-Hartman wrote:
> >>+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";
> >This is a lot more stuff than just debug port, it should be in sysfs
> >as individual files, not one big one that you somehow have to parse in
> >order to determine this information.
> >
> 
> Hi Greg,
> 
> It's hard to put each extended capability into a individual sysfs file.

Agreed.

> The extended capabilities are optional. One extended capability
> might be supported in one hardware, but not in another. Also,
> there are many "vendor defined" capabilities (ID range 192-255).
> The vendor defined capabilities are not defined in xhci spec and
> they could be used by the hardware vendor for various purposes.
> 
> The purpose of this patch is to let user know what kind of extended
> capabilities does a host controller supported. For example, on
> one of my develop machines, it prints,
> 
> @addr(virt)        CAP_ID    Description
> @ffffc90001c88000    02    Supported Protocol
> @ffffc90001c88020    02    Supported Protocol
> @ffffc90001c88070    c0    Vendor Defined
> @ffffc90001c8846c    01    USB Legacy Support
> @ffffc90001c884f4    c6    Vendor Defined
> @ffffc90001c88500    c7    Vendor Defined
> @ffffc90001c88600    c2    Vendor Defined
> @ffffc90001c88700    0a    USB Debug Capability
> @ffffc90001c88740    c3    Vendor Defined
> @ffffc90001c88800    c4    Vendor Defined
> @ffffc90001c88900    c5    Vendor Defined
> 
> With this output I know that "USB Debug Capability" is supported
> in my machine.

First off, why are you printing the address out?  Userspace never needs
to see that.  Why not just iterate through the protocols and export the
information as different files:
	protocol_XX
and if the file is present or not describes if the hardware supports it
or not.

The issue with debugfs is that it is not enabled on all systems, and
only can be read by the root user, so it is hard for people to find this
information out if they want to do normal things with the hardware.

But, if this really is only a debug thing, then it can say a debugfs
file, but realize that almost no one will be able to see it (and even
then, don't export the kernel addresses of the hardware.)

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257765 — [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

FromLu Baolu <baolu.lu@linux.intel.com>
Date2015-10-28 09:10 +0100
Subject[PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qotXZ-8vm-49@gated-at.bofh.it>
In reply to#1257761
This patch add dbc debug device support in usb_debug driver.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index ca2fa5b..d4903b0 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -32,7 +32,18 @@ static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x0525, 0x127a) },
 	{ },
 };
-MODULE_DEVICE_TABLE(usb, id_table);
+
+static const struct usb_device_id dbc_id_table[] = {
+	{ USB_DEVICE(0x1d6b, 0x0004) },
+	{ },
+};
+
+static const struct usb_device_id id_table_combined[] = {
+	{ USB_DEVICE(0x0525, 0x127a) },
+	{ USB_DEVICE(0x1d6b, 0x0004) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table_combined);
 
 /* This HW really does not support a serial break, so one will be
  * emulated when ever the break state is set to true.
@@ -71,9 +82,21 @@ static struct usb_serial_driver debug_device = {
 	.process_read_urb =	usb_debug_process_read_urb,
 };
 
+static struct usb_serial_driver dbc_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"xhci_dbc",
+	},
+	.id_table =		dbc_id_table,
+	.num_ports =		1,
+	.bulk_out_size =	1024,
+	.break_ctl =		usb_debug_break_ctl,
+	.process_read_urb =	usb_debug_process_read_urb,
+};
+
 static struct usb_serial_driver * const serial_drivers[] = {
-	&debug_device, NULL
+	&debug_device, &dbc_device, NULL
 };
 
-module_usb_serial_driver(serial_drivers, id_table);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 MODULE_LICENSE("GPL");
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257831 — Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

FromJohan Hovold <johan@kernel.org>
Date2015-10-28 10:20 +0100
SubjectRe: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qov3H-If-19@gated-at.bofh.it>
In reply to#1257765
On Wed, Oct 28, 2015 at 04:00:42PM +0800, Lu Baolu wrote:
> This patch add dbc debug device support in usb_debug driver.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
>  1 file changed, 26 insertions(+), 3 deletions(-)
 
> +static struct usb_serial_driver dbc_device = {
> +	.driver = {
> +		.owner =	THIS_MODULE,
> +		.name =		"xhci_dbc",
> +	},
> +	.id_table =		dbc_id_table,
> +	.num_ports =		1,
> +	.bulk_out_size =	1024,

No need to set this unless you need a larger (or smaller for ehci)
buffer than the endpoint size.

Johan
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1258515 — Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

From"Lu, Baolu" <baolu.lu@linux.intel.com>
Date2015-10-29 02:30 +0100
SubjectRe: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qoKcq-21b-3@gated-at.bofh.it>
In reply to#1257831

On 10/28/2015 05:10 PM, Johan Hovold wrote:
> On Wed, Oct 28, 2015 at 04:00:42PM +0800, Lu Baolu wrote:
>> This patch add dbc debug device support in usb_debug driver.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
>>   1 file changed, 26 insertions(+), 3 deletions(-)
>   
>> +static struct usb_serial_driver dbc_device = {
>> +	.driver = {
>> +		.owner =	THIS_MODULE,
>> +		.name =		"xhci_dbc",
>> +	},
>> +	.id_table =		dbc_id_table,
>> +	.num_ports =		1,
>> +	.bulk_out_size =	1024,
> No need to set this unless you need a larger (or smaller for ehci)
> buffer than the endpoint size.

I will remove it in v2. Thanks for pointing this out.

>
> Johan
>

Thanks,
Baolu
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257952 — Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

FromGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Date2015-10-28 13:40 +0100
SubjectRe: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qoybg-2Bd-13@gated-at.bofh.it>
In reply to#1257765
On Wed, Oct 28, 2015 at 04:00:42PM +0800, Lu Baolu wrote:
> This patch add dbc debug device support in usb_debug driver.
> 
> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> ---
>  drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
>  1 file changed, 26 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
> index ca2fa5b..d4903b0 100644
> --- a/drivers/usb/serial/usb_debug.c
> +++ b/drivers/usb/serial/usb_debug.c
> @@ -32,7 +32,18 @@ static const struct usb_device_id id_table[] = {
>  	{ USB_DEVICE(0x0525, 0x127a) },
>  	{ },
>  };
> -MODULE_DEVICE_TABLE(usb, id_table);
> +
> +static const struct usb_device_id dbc_id_table[] = {
> +	{ USB_DEVICE(0x1d6b, 0x0004) },
> +	{ },
> +};
> +
> +static const struct usb_device_id id_table_combined[] = {
> +	{ USB_DEVICE(0x0525, 0x127a) },
> +	{ USB_DEVICE(0x1d6b, 0x0004) },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(usb, id_table_combined);

You shouldn't need a "combined" module device table anymore, the module
core was changed a while ago to remove that restriction, you should be
able to just multiple exports of MODULE_DEVICE_TABLE and everything
should "just work" on the export side.  Now it might not work on the usb
core side, but that's a different issue...

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1258520 — Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

From"Lu, Baolu" <baolu.lu@linux.intel.com>
Date2015-10-29 02:50 +0100
SubjectRe: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qoKvM-27t-11@gated-at.bofh.it>
In reply to#1257952

On 10/28/2015 08:33 PM, Greg Kroah-Hartman wrote:
> On Wed, Oct 28, 2015 at 04:00:42PM +0800, Lu Baolu wrote:
>> This patch add dbc debug device support in usb_debug driver.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
>>   1 file changed, 26 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
>> index ca2fa5b..d4903b0 100644
>> --- a/drivers/usb/serial/usb_debug.c
>> +++ b/drivers/usb/serial/usb_debug.c
>> @@ -32,7 +32,18 @@ static const struct usb_device_id id_table[] = {
>>   	{ USB_DEVICE(0x0525, 0x127a) },
>>   	{ },
>>   };
>> -MODULE_DEVICE_TABLE(usb, id_table);
>> +
>> +static const struct usb_device_id dbc_id_table[] = {
>> +	{ USB_DEVICE(0x1d6b, 0x0004) },
>> +	{ },
>> +};
>> +
>> +static const struct usb_device_id id_table_combined[] = {
>> +	{ USB_DEVICE(0x0525, 0x127a) },
>> +	{ USB_DEVICE(0x1d6b, 0x0004) },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(usb, id_table_combined);
> You shouldn't need a "combined" module device table anymore, the module
> core was changed a while ago to remove that restriction, you should be
> able to just multiple exports of MODULE_DEVICE_TABLE and everything
> should "just work" on the export side.  Now it might not work on the usb
> core side, but that's a different issue...

Thanks for pointing this out. I will re-factor this code in v2 patch.

>
> thanks,
>
> greg k-h
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1259432 — Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

From"Lu, Baolu" <baolu.lu@linux.intel.com>
Date2015-10-30 12:50 +0100
SubjectRe: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qpglY-5iu-23@gated-at.bofh.it>
In reply to#1257952

On 10/28/2015 08:33 PM, Greg Kroah-Hartman wrote:
> On Wed, Oct 28, 2015 at 04:00:42PM +0800, Lu Baolu wrote:
>> This patch add dbc debug device support in usb_debug driver.
>>
>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>> ---
>>   drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
>>   1 file changed, 26 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
>> index ca2fa5b..d4903b0 100644
>> --- a/drivers/usb/serial/usb_debug.c
>> +++ b/drivers/usb/serial/usb_debug.c
>> @@ -32,7 +32,18 @@ static const struct usb_device_id id_table[] = {
>>   	{ USB_DEVICE(0x0525, 0x127a) },
>>   	{ },
>>   };
>> -MODULE_DEVICE_TABLE(usb, id_table);
>> +
>> +static const struct usb_device_id dbc_id_table[] = {
>> +	{ USB_DEVICE(0x1d6b, 0x0004) },
>> +	{ },
>> +};
>> +
>> +static const struct usb_device_id id_table_combined[] = {
>> +	{ USB_DEVICE(0x0525, 0x127a) },
>> +	{ USB_DEVICE(0x1d6b, 0x0004) },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(usb, id_table_combined);
> You shouldn't need a "combined" module device table anymore, the module
> core was changed a while ago to remove that restriction, you should be
> able to just multiple exports of MODULE_DEVICE_TABLE and everything
> should "just work" on the export side.  Now it might not work on the usb
> core side, but that's a different issue...

Before I dive into the serial driver code, can anybody tell me, if
I remove the "combined" module device table, what should I
specify the second parameter for module_usb_serial_driver()?

The previous declaration is,

module_usb_serial_driver(serial_drivers, id_table_combined);

Thanks,
Baolu

>
> thanks,
>
> greg k-h
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1259557 — Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

FromGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Date2015-10-30 15:50 +0100
SubjectRe: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qpjaa-70R-7@gated-at.bofh.it>
In reply to#1259432
On Fri, Oct 30, 2015 at 07:46:45PM +0800, Lu, Baolu wrote:
> 
> 
> On 10/28/2015 08:33 PM, Greg Kroah-Hartman wrote:
> >On Wed, Oct 28, 2015 at 04:00:42PM +0800, Lu Baolu wrote:
> >>This patch add dbc debug device support in usb_debug driver.
> >>
> >>Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> >>---
> >>  drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
> >>  1 file changed, 26 insertions(+), 3 deletions(-)
> >>
> >>diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
> >>index ca2fa5b..d4903b0 100644
> >>--- a/drivers/usb/serial/usb_debug.c
> >>+++ b/drivers/usb/serial/usb_debug.c
> >>@@ -32,7 +32,18 @@ static const struct usb_device_id id_table[] = {
> >>  	{ USB_DEVICE(0x0525, 0x127a) },
> >>  	{ },
> >>  };
> >>-MODULE_DEVICE_TABLE(usb, id_table);
> >>+
> >>+static const struct usb_device_id dbc_id_table[] = {
> >>+	{ USB_DEVICE(0x1d6b, 0x0004) },
> >>+	{ },
> >>+};
> >>+
> >>+static const struct usb_device_id id_table_combined[] = {
> >>+	{ USB_DEVICE(0x0525, 0x127a) },
> >>+	{ USB_DEVICE(0x1d6b, 0x0004) },
> >>+	{ },
> >>+};
> >>+MODULE_DEVICE_TABLE(usb, id_table_combined);
> >You shouldn't need a "combined" module device table anymore, the module
> >core was changed a while ago to remove that restriction, you should be
> >able to just multiple exports of MODULE_DEVICE_TABLE and everything
> >should "just work" on the export side.  Now it might not work on the usb
> >core side, but that's a different issue...
> 
> Before I dive into the serial driver code, can anybody tell me, if
> I remove the "combined" module device table, what should I
> specify the second parameter for module_usb_serial_driver()?
> 
> The previous declaration is,
> 
> module_usb_serial_driver(serial_drivers, id_table_combined);

Yeah, that's the issue I was alluding to here, maybe this will not work
just yet for USB serial drivers, sorry to lead you down the wrong path.
Your original patch should be fine for now.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1259936 — Re: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device

From"Lu, Baolu" <baolu.lu@linux.intel.com>
Date2015-10-31 06:40 +0100
SubjectRe: [PATCH 11/12] usb: serial: usb_debug: add support for dbc debug device
Message-ID<qpx3s-7j8-5@gated-at.bofh.it>
In reply to#1259557

On 10/30/2015 10:41 PM, Greg Kroah-Hartman wrote:
> On Fri, Oct 30, 2015 at 07:46:45PM +0800, Lu, Baolu wrote:
>>
>> On 10/28/2015 08:33 PM, Greg Kroah-Hartman wrote:
>>> On Wed, Oct 28, 2015 at 04:00:42PM +0800, Lu Baolu wrote:
>>>> This patch add dbc debug device support in usb_debug driver.
>>>>
>>>> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
>>>> ---
>>>>   drivers/usb/serial/usb_debug.c | 29 ++++++++++++++++++++++++++---
>>>>   1 file changed, 26 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
>>>> index ca2fa5b..d4903b0 100644
>>>> --- a/drivers/usb/serial/usb_debug.c
>>>> +++ b/drivers/usb/serial/usb_debug.c
>>>> @@ -32,7 +32,18 @@ static const struct usb_device_id id_table[] = {
>>>>   	{ USB_DEVICE(0x0525, 0x127a) },
>>>>   	{ },
>>>>   };
>>>> -MODULE_DEVICE_TABLE(usb, id_table);
>>>> +
>>>> +static const struct usb_device_id dbc_id_table[] = {
>>>> +	{ USB_DEVICE(0x1d6b, 0x0004) },
>>>> +	{ },
>>>> +};
>>>> +
>>>> +static const struct usb_device_id id_table_combined[] = {
>>>> +	{ USB_DEVICE(0x0525, 0x127a) },
>>>> +	{ USB_DEVICE(0x1d6b, 0x0004) },
>>>> +	{ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(usb, id_table_combined);
>>> You shouldn't need a "combined" module device table anymore, the module
>>> core was changed a while ago to remove that restriction, you should be
>>> able to just multiple exports of MODULE_DEVICE_TABLE and everything
>>> should "just work" on the export side.  Now it might not work on the usb
>>> core side, but that's a different issue...
>> Before I dive into the serial driver code, can anybody tell me, if
>> I remove the "combined" module device table, what should I
>> specify the second parameter for module_usb_serial_driver()?
>>
>> The previous declaration is,
>>
>> module_usb_serial_driver(serial_drivers, id_table_combined);
> Yeah, that's the issue I was alluding to here, maybe this will not work
> just yet for USB serial drivers, sorry to lead you down the wrong path.
> Your original patch should be fine for now.

Okay, I will keep that patch.

>
> thanks,
>
> greg k-h

Thanks,
Baolu

> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257766 — [PATCH 06/12] usb: xhci: dbc: add bulk out and bulk in interfaces

FromLu Baolu <baolu.lu@linux.intel.com>
Date2015-10-28 09:10 +0100
Subject[PATCH 06/12] usb: xhci: dbc: add bulk out and bulk in interfaces
Message-ID<qotXZ-8vm-57@gated-at.bofh.it>
In reply to#1257761
This patch adds interfaces for bulk out and bulk in ops. These
interfaces could be used to implement early printk bootconsole
or hook to various system debuggers.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 drivers/usb/early/xhci-dbc.c | 373 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/xhci-dbc.h |  30 ++++
 2 files changed, 403 insertions(+)

diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index b36a527..f51daa4 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -219,11 +219,21 @@ static void xdbc_dbg_dump_data(char *str)
 	xdbc_dbg_dump_string("String Descriptor:");
 }
 
+static void xdbc_dbg_dump_trb(struct xdbc_trb *trb, char *str)
+{
+	xdbc_trace("DBC trb: %s\n", str);
+	xdbc_trace("@%016llx %08x %08x %08x %08x\n", (u64)__pa(trb),
+				le32_to_cpu(trb->field[0]),
+				le32_to_cpu(trb->field[1]),
+				le32_to_cpu(trb->field[2]),
+				le32_to_cpu(trb->field[3]));
+}
 #else
 static inline void xdbc_trace(const char *fmt, ...) { }
 static inline void xdbc_dump_debug_buffer(void) { }
 static inline void xdbc_dbg_dump_regs(char *str) { }
 static inline void xdbc_dbg_dump_data(char *str) { }
+static inline void xdbc_dbg_dump_trb(struct xdbc_trb *trb, char *str) { }
 #endif	/* DBC_DEBUG */
 
 /*
@@ -334,6 +344,7 @@ static void *xdbc_get_page(dma_addr_t *dma_addr,
 	static char in_ring_page[PAGE_SIZE] __aligned(PAGE_SIZE);
 	static char out_ring_page[PAGE_SIZE] __aligned(PAGE_SIZE);
 	static char table_page[PAGE_SIZE] __aligned(PAGE_SIZE);
+	static char bulk_buf_page[PAGE_SIZE] __aligned(PAGE_SIZE);
 
 	switch (type) {
 	case XDBC_PAGE_EVENT:
@@ -348,6 +359,9 @@ static void *xdbc_get_page(dma_addr_t *dma_addr,
 	case XDBC_PAGE_TABLE:
 		virt = (void *)table_page;
 		break;
+	case XDBC_PAGE_BUFFER:
+		virt = (void *)bulk_buf_page;
+		break;
 	default:
 		return NULL;
 	}
@@ -707,6 +721,12 @@ static int xdbc_mem_init(void)
 	dev_info = cpu_to_le32((XDBC_DEVICE_REV << 16) | XDBC_PRODUCT_ID);
 	writel(dev_info, &xdbcp->xdbc_reg->devinfo2);
 
+	/* get and store the transfer buffer */
+	xdbcp->out_buf = xdbc_get_page(&xdbcp->out_dma,
+			XDBC_PAGE_BUFFER);
+	xdbcp->in_buf = xdbcp->out_buf + XDBC_MAX_PACKET;
+	xdbcp->in_dma = xdbcp->out_dma + XDBC_MAX_PACKET;
+
 	return 0;
 }
 
@@ -802,6 +822,9 @@ static int xdbc_start(void)
 
 	xdbc_trace("root hub port number %d\n", DCST_DPN(status));
 
+	xdbcp->in_ep_state = EP_RUNNING;
+	xdbcp->out_ep_state = EP_RUNNING;
+
 	xdbc_trace("DbC is running now, control 0x%08x\n",
 			readl(&xdbcp->xdbc_reg->control));
 
@@ -895,3 +918,353 @@ int __init early_xdbc_init(char *s)
 
 	return 0;
 }
+
+static void xdbc_queue_trb(struct xdbc_ring *ring,
+		u32 field1, u32 field2, u32 field3, u32 field4)
+{
+	struct xdbc_trb *trb, *link_trb;
+
+	trb = ring->enqueue;
+	trb->field[0] = cpu_to_le32(field1);
+	trb->field[1] = cpu_to_le32(field2);
+	trb->field[2] = cpu_to_le32(field3);
+	trb->field[3] = cpu_to_le32(field4);
+
+	xdbc_dbg_dump_trb(trb, "enqueue trb");
+
+	++(ring->enqueue);
+	if (ring->enqueue >= &ring->segment->trbs[TRBS_PER_SEGMENT - 1]) {
+		link_trb = ring->enqueue;
+		if (ring->cycle_state)
+			link_trb->field[3] |= cpu_to_le32(TRB_CYCLE);
+		else
+			link_trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
+
+		ring->enqueue = ring->segment->trbs;
+		ring->cycle_state ^= 1;
+	}
+}
+
+static void xdbc_ring_doorbell(int target)
+{
+	writel(DOOR_BELL_TARGET(target), &xdbcp->xdbc_reg->doorbell);
+}
+
+static void xdbc_handle_port_status(struct xdbc_trb *evt_trb)
+{
+	u32 port_reg;
+
+	port_reg = readl(&xdbcp->xdbc_reg->portsc);
+
+	if (port_reg & PORTSC_CSC) {
+		xdbc_trace("%s: connect status change event\n", __func__);
+		writel(port_reg | PORTSC_CSC, &xdbcp->xdbc_reg->portsc);
+		port_reg = readl(&xdbcp->xdbc_reg->portsc);
+	}
+
+	if (port_reg & PORTSC_PRC) {
+		xdbc_trace("%s: port reset change event\n", __func__);
+		writel(port_reg | PORTSC_PRC, &xdbcp->xdbc_reg->portsc);
+		port_reg = readl(&xdbcp->xdbc_reg->portsc);
+	}
+
+	if (port_reg & PORTSC_PLC) {
+		xdbc_trace("%s: port link status change event\n", __func__);
+		writel(port_reg | PORTSC_PLC, &xdbcp->xdbc_reg->portsc);
+		port_reg = readl(&xdbcp->xdbc_reg->portsc);
+	}
+
+	if (port_reg & PORTSC_CEC) {
+		xdbc_trace("%s: config error change\n", __func__);
+		writel(port_reg | PORTSC_CEC, &xdbcp->xdbc_reg->portsc);
+		port_reg = readl(&xdbcp->xdbc_reg->portsc);
+	}
+}
+
+static void xdbc_handle_tx_event(struct xdbc_trb *evt_trb)
+{
+	u32 comp_code;
+	u32 tx_dma_high, tx_dma_low;
+	u64 in_dma, out_dma;
+	size_t remain_length;
+	int ep_id;
+
+	tx_dma_low = le32_to_cpu(evt_trb->field[0]);
+	tx_dma_high = le32_to_cpu(evt_trb->field[1]);
+	comp_code = GET_COMP_CODE(le32_to_cpu(evt_trb->field[2]));
+	remain_length = EVENT_TRB_LEN(le32_to_cpu(evt_trb->field[2]));
+	ep_id = TRB_TO_EP_ID(le32_to_cpu(evt_trb->field[3]));
+	in_dma = __pa(xdbcp->in_pending);
+	out_dma = __pa(xdbcp->out_pending);
+
+	/*
+	 * Possible Completion Codes for DbC Transfer Event are Success,
+	 * Stall Error, USB Transaction Error, Babble Detected Error,
+	 * TRB Error, Short Packet, Undefined Error, Event Ring Full Error,
+	 * and Vendor Defined Error. TRB error, undefined error and vendor
+	 * defined error will result in HOT/HIT set and be handled the same
+	 * way as Stall error.
+	 */
+	switch (comp_code) {
+	case COMP_SUCCESS:
+		remain_length = 0;
+	case COMP_SHORT_TX:
+		xdbc_trace("%s: endpoint %d remains %d bytes\n", __func__,
+			ep_id, remain_length);
+		break;
+	case COMP_TRB_ERR:
+	case COMP_BABBLE:
+	case COMP_TX_ERR:
+	case COMP_STALL:
+	default:
+		xdbc_trace("%s: endpoint %d halted\n", __func__, ep_id);
+		if (ep_id == XDBC_EPID_OUT)
+			xdbcp->out_ep_state = EP_HALTED;
+		if (ep_id == XDBC_EPID_IN)
+			xdbcp->in_ep_state = EP_HALTED;
+
+		break;
+	}
+
+	if (lower_32_bits(in_dma) == tx_dma_low &&
+			upper_32_bits(in_dma) == tx_dma_high) {
+		xdbcp->in_complete = comp_code;
+		xdbcp->in_complete_length =
+				(remain_length > xdbcp->in_length) ?
+				0 : xdbcp->in_length - remain_length;
+	}
+
+	if (lower_32_bits(out_dma) == tx_dma_low &&
+			upper_32_bits(out_dma) == tx_dma_high) {
+		xdbcp->out_complete = comp_code;
+		xdbcp->out_complete_length =
+				(remain_length > xdbcp->out_length) ?
+				0 : xdbcp->out_length - remain_length;
+	}
+}
+
+static void xdbc_handle_events(void)
+{
+	struct xdbc_trb *evt_trb;
+	bool update_erdp = false;
+
+	evt_trb = xdbcp->evt_ring.dequeue;
+	while ((le32_to_cpu(evt_trb->field[3]) & TRB_CYCLE) ==
+			xdbcp->evt_ring.cycle_state) {
+		/*
+		 * Memory barrier to ensure software sees the trbs
+		 * enqueued by hardware.
+		 */
+		rmb();
+
+		xdbc_dbg_dump_trb(evt_trb, "event trb");
+
+		/* FIXME: Handle more event types. */
+		switch ((le32_to_cpu(evt_trb->field[3]) & TRB_TYPE_BITMASK)) {
+		case TRB_TYPE(TRB_PORT_STATUS):
+			xdbc_handle_port_status(evt_trb);
+			break;
+		case TRB_TYPE(TRB_TRANSFER):
+			xdbc_handle_tx_event(evt_trb);
+			break;
+		default:
+			break;
+		}
+
+		/* advance to the next trb */
+		++(xdbcp->evt_ring.dequeue);
+		if (xdbcp->evt_ring.dequeue ==
+				&xdbcp->evt_seg.trbs[TRBS_PER_SEGMENT]) {
+			xdbcp->evt_ring.dequeue = xdbcp->evt_seg.trbs;
+			xdbcp->evt_ring.cycle_state ^= 1;
+		}
+
+		evt_trb = xdbcp->evt_ring.dequeue;
+		update_erdp = true;
+	}
+
+	/* update event ring dequeue pointer */
+	if (update_erdp)
+		xdbc_write64(__pa(xdbcp->evt_ring.dequeue),
+				&xdbcp->xdbc_reg->erdp);
+}
+
+/*
+ * Check and dispatch events in event ring. It also checks status
+ * of hardware. This function will be called from multiple threads.
+ * An atomic lock is applied to protect the access of event ring.
+ */
+static int xdbc_check_event(void)
+{
+	/* event ring is under checking by other thread? */
+	if (!test_bit(XDBC_ATOMIC_EVENT, &xdbcp->atomic_flags) &&
+			!test_and_set_bit(XDBC_ATOMIC_EVENT,
+			&xdbcp->atomic_flags))
+		return 0;
+
+	xdbc_handle_events();
+
+	test_and_clear_bit(XDBC_ATOMIC_EVENT, &xdbcp->atomic_flags);
+
+	return 0;
+}
+
+#define	BULK_IN_COMPLETED(p)	((xdbcp->in_pending == (p)) && \
+				 xdbcp->in_complete)
+#define	BULK_OUT_COMPLETED(p)	((xdbcp->out_pending == (p)) && \
+				 xdbcp->out_complete)
+
+/*
+ * Wait for a bulk-in or bulk-out transfer completion or timed out.
+ * Return count of the actually transferred bytes or error.
+ */
+static int xdbc_wait_until_bulk_done(struct xdbc_trb *trb, int loops)
+{
+	int timeout = 0;
+	bool read;
+
+	if (trb != xdbcp->in_pending &&
+			trb != xdbcp->out_pending)
+		return -EINVAL;
+
+	read = (trb == xdbcp->in_pending);
+
+	do {
+		if (xdbc_check_event() < 0)
+			break;
+
+		if (read && BULK_IN_COMPLETED(trb)) {
+			if (xdbcp->in_ep_state == EP_HALTED)
+				return -EAGAIN;
+			else
+				return xdbcp->in_complete_length;
+		}
+
+		if (!read && BULK_OUT_COMPLETED(trb)) {
+			if (xdbcp->out_ep_state == EP_HALTED)
+				return -EAGAIN;
+			else
+				return xdbcp->out_complete_length;
+		}
+
+		xdbc_udelay(10);
+	} while ((timeout++ < loops) || !loops);
+
+	return -EIO;
+}
+
+static int xdbc_bulk_transfer(void *data, int size, int loops, bool read)
+{
+	u64 addr;
+	u32 length, control;
+	struct xdbc_trb *trb;
+	struct xdbc_ring *ring;
+	u32 cycle;
+	int ret;
+
+	if (size > XDBC_MAX_PACKET) {
+		xdbc_trace("%s: bad parameter, size %d", __func__, size);
+		return -EINVAL;
+	}
+
+	ring = (read ? &xdbcp->in_ring : &xdbcp->out_ring);
+	trb = ring->enqueue;
+	cycle = ring->cycle_state;
+
+	length = TRB_LEN(size);
+	control = TRB_TYPE(TRB_NORMAL) | TRB_IOC;
+
+	if (cycle)
+		control &= cpu_to_le32(~TRB_CYCLE);
+	else
+		control |= cpu_to_le32(TRB_CYCLE);
+
+	if (read) {
+		memset(xdbcp->in_buf, 0, XDBC_MAX_PACKET);
+		addr = xdbcp->in_dma;
+
+		xdbcp->in_pending = trb;
+		xdbcp->in_length = size;
+		xdbcp->in_complete = 0;
+		xdbcp->in_complete_length = 0;
+	} else {
+		memcpy(xdbcp->out_buf, data, size);
+		addr = xdbcp->out_dma;
+
+		xdbcp->out_pending = trb;
+		xdbcp->out_length = size;
+		xdbcp->out_complete = 0;
+		xdbcp->out_complete_length = 0;
+	}
+
+	xdbc_queue_trb(ring, lower_32_bits(addr),
+			upper_32_bits(addr),
+			length, control);
+
+	/*
+	 * Memory barrier to ensure hardware sees the trbs
+	 * enqueued above.
+	 */
+	wmb();
+	if (cycle)
+		trb->field[3] |= cpu_to_le32(cycle);
+	else
+		trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
+
+	xdbc_ring_doorbell(read ? IN_EP_DOORBELL : OUT_EP_DOORBELL);
+
+	ret = xdbc_wait_until_bulk_done(trb, loops);
+
+	if (read)
+		xdbcp->in_pending = NULL;
+	else
+		xdbcp->out_pending = NULL;
+
+	if (ret > 0) {
+		if (read)
+			memcpy(data, xdbcp->in_buf, size);
+		else
+			memset(xdbcp->out_buf, 0, XDBC_MAX_PACKET);
+	} else {
+		xdbc_trace("%s: bulk %s transfer results in error %d\n",
+				__func__, read ? "in" : "out", ret);
+	}
+
+	return ret;
+}
+
+int xdbc_bulk_read(void *data, int size, int loops)
+{
+	int ret;
+
+	do {
+		if (!test_bit(XDBC_ATOMIC_BULKIN, &xdbcp->atomic_flags) &&
+				!test_and_set_bit(XDBC_ATOMIC_BULKIN,
+				&xdbcp->atomic_flags))
+			break;
+	} while (1);
+
+	ret = xdbc_bulk_transfer(data, size, loops, true);
+
+	test_and_clear_bit(XDBC_ATOMIC_BULKIN, &xdbcp->atomic_flags);
+
+	return ret;
+}
+
+int xdbc_bulk_write(const char *bytes, int size)
+{
+	int ret;
+
+	do {
+		if (!test_bit(XDBC_ATOMIC_BULKOUT, &xdbcp->atomic_flags) &&
+				!test_and_set_bit(XDBC_ATOMIC_BULKOUT,
+				&xdbcp->atomic_flags))
+			break;
+	} while (1);
+
+	ret = xdbc_bulk_transfer((void *)bytes, size, XDBC_LOOPS, false);
+
+	test_and_clear_bit(XDBC_ATOMIC_BULKOUT, &xdbcp->atomic_flags);
+
+	return ret;
+}
diff --git a/include/linux/usb/xhci-dbc.h b/include/linux/usb/xhci-dbc.h
index fc0ef9a..289ba58 100644
--- a/include/linux/usb/xhci-dbc.h
+++ b/include/linux/usb/xhci-dbc.h
@@ -120,8 +120,17 @@ enum xdbc_page_type {
 	XDBC_PAGE_TXIN,
 	XDBC_PAGE_TXOUT,
 	XDBC_PAGE_TABLE,
+	XDBC_PAGE_BUFFER,
 };
 
+enum xdbc_ep_state {
+	EP_DISABLED,
+	EP_RUNNING,
+	EP_HALTED,
+};
+#define	XDBC_EPID_OUT	2
+#define	XDBC_EPID_IN	1
+
 struct xdbc_state {
 	/* pci device info*/
 	u32		bus;
@@ -170,13 +179,34 @@ struct xdbc_state {
 	/* bulk OUT endpoint */
 	struct xdbc_ring	out_ring;
 	struct xdbc_segment	out_seg;
+	void			*out_buf;
+	dma_addr_t		out_dma;
+	struct xdbc_trb		*out_pending;		/* IN */
+	size_t			out_length;		/* IN */
+	u32			out_complete;		/* OUT */
+	size_t			out_complete_length;	/* OUT */
+	enum xdbc_ep_state	out_ep_state;
 
 	/* bulk IN endpoint */
 	struct xdbc_ring	in_ring;
 	struct xdbc_segment	in_seg;
+	void			*in_buf;
+	dma_addr_t		in_dma;
+	struct xdbc_trb		*in_pending;		/* IN */
+	size_t			in_length;		/* IN */
+	u32			in_complete;		/* OUT */
+	size_t			in_complete_length;	/* OUT */
+	enum xdbc_ep_state	in_ep_state;
+
+	/* atomic flags */
+	unsigned long		atomic_flags;
+#define	XDBC_ATOMIC_BULKOUT	0
+#define	XDBC_ATOMIC_BULKIN	1
+#define	XDBC_ATOMIC_EVENT	2
 };
 
 #define	XDBC_MAX_PACKET		1024
+#define	XDBC_LOOPS		1000
 
 /* door bell target */
 #define	OUT_EP_DOORBELL		0
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1257767 — [PATCH 03/12] usb: xhci: dbc: probe and setup xhci debug capability

FromLu Baolu <baolu.lu@linux.intel.com>
Date2015-10-28 09:10 +0100
Subject[PATCH 03/12] usb: xhci: dbc: probe and setup xhci debug capability
Message-ID<qotXY-8vm-17@gated-at.bofh.it>
In reply to#1257761
xHCI debug capability (DbC) is an optional functionality provided
by an xHCI host controller. Software learns this capability by
walking through the extended capability list in mmio of the host.

This patch introduces the code to probe and initialize the debug
capability hardware during early boot. With hardware initialization
done, the debug target (system under debug which has DbC enabled)
will present a debug device through the debug port. The debug device
is fully compliant with the USB framework and provides the equivalent
of a very high performance (USB3) full-duplex serial link between the
debug host and target.

Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
 MAINTAINERS                  |   7 +
 arch/x86/Kconfig.debug       |  12 +
 drivers/usb/early/Makefile   |   1 +
 drivers/usb/early/xhci-dbc.c | 787 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/usb/xhci-dbc.h | 187 ++++++++++
 5 files changed, 994 insertions(+)
 create mode 100644 drivers/usb/early/xhci-dbc.c
 create mode 100644 include/linux/usb/xhci-dbc.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 0425167..585a369 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11040,6 +11040,13 @@ S:	Supported
 F:	drivers/usb/host/xhci*
 F:	drivers/usb/host/pci-quirks*
 
+USB XHCI DEBUG PORT
+M:	Lu Baolu <baolu.lu@linux.intel.com>
+L:	linux-usb@vger.kernel.org
+S:	Supported
+F:	drivers/usb/early/xhci-dbc.c
+F:	include/linux/usb/xhci-dbc.h
+
 USB ZD1201 DRIVER
 L:	linux-wireless@vger.kernel.org
 W:	http://linux-lc100020.sourceforge.net
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index d8c0d32..8d95abd 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -65,6 +65,18 @@ config EARLY_PRINTK_EFI
 	  This is useful for kernel debugging when your machine crashes very
 	  early before the console code is initialized.
 
+config EARLY_PRINTK_XDBC
+	bool "Early printk via xHCI debug port"
+	depends on EARLY_PRINTK && PCI
+	---help---
+	  Write kernel log output directly into the xHCI debug port.
+
+	  This is useful for kernel debugging when your machine crashes very
+	  early before the console code is initialized. For normal operation
+	  it is not recommended because it looks ugly and doesn't cooperate
+	  with klogd/syslogd or the X server. You should normally N here,
+	  unless you want to debug such a crash.
+
 config X86_PTDUMP
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
diff --git a/drivers/usb/early/Makefile b/drivers/usb/early/Makefile
index 24bbe51..2db5906 100644
--- a/drivers/usb/early/Makefile
+++ b/drivers/usb/early/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
+obj-$(CONFIG_EARLY_PRINTK_XDBC) += xhci-dbc.o
diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
new file mode 100644
index 0000000..22a1de9
--- /dev/null
+++ b/drivers/usb/early/xhci-dbc.c
@@ -0,0 +1,787 @@
+/**
+ * xhci-dbc.c - xHCI debug capability driver
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Author: Lu Baolu <baolu.lu@linux.intel.com>
+ * Some code shared with EHCI debug port and xHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/bootmem.h>
+#include <linux/io.h>
+#include <asm/pci-direct.h>
+#include <asm/fixmap.h>
+#include <linux/bcd.h>
+#include <linux/export.h>
+#include <linux/version.h>
+#include <linux/usb/xhci-dbc.h>
+
+#include "../host/xhci.h"
+
+#define	XDBC_PROTOCOL		1	/* GNU Remote Debug Command Set */
+#define	XDBC_VENDOR_ID		0x1d6b	/* Linux Foundation 0x1d6b */
+#define	XDBC_PRODUCT_ID		0x0004	/* __le16 idProduct; device 0004 */
+#define	XDBC_DEVICE_REV		0x0010	/* 0.10 */
+
+static struct xdbc_state xdbc_stat;
+static struct xdbc_state *xdbcp = &xdbc_stat;
+
+#ifdef DBC_DEBUG
+/* place holder */
+#define	xdbc_trace	printk
+static void xdbc_dbg_dump_regs(char *str)
+{
+	if (!xdbcp->xdbc_reg) {
+		xdbc_trace("register not mapped\n");
+		return;
+	}
+
+	xdbc_trace("XDBC registers: %s\n", str);
+	xdbc_trace("  Capability: %08x\n",
+			readl(&xdbcp->xdbc_reg->capability));
+	xdbc_trace("  Door bell: %08x\n",
+			readl(&xdbcp->xdbc_reg->doorbell));
+	xdbc_trace("  Event Ring Segment Table Size: %08x\n",
+			readl(&xdbcp->xdbc_reg->ersts));
+	xdbc_trace("  Event Ring Segment Table Base Address: %16llx\n",
+			xdbc_read64(&xdbcp->xdbc_reg->erstba));
+	xdbc_trace("  Event Ring Dequeue Pointer: %16llx\n",
+			xdbc_read64(&xdbcp->xdbc_reg->erdp));
+	xdbc_trace("  Port status and control: %08x\n",
+			readl(&xdbcp->xdbc_reg->portsc));
+	xdbc_trace("  Debug Capability Context Pointer: %16llx\n",
+			xdbc_read64(&xdbcp->xdbc_reg->dccp));
+	xdbc_trace("  Device Descriptor Info Register 1: %08x\n",
+			readl(&xdbcp->xdbc_reg->devinfo1));
+	xdbc_trace("  Device Descriptor Info Register 2: %08x\n",
+			readl(&xdbcp->xdbc_reg->devinfo2));
+}
+
+static void xdbc_dbg_dump_info_context(char *str)
+{
+	int i;
+	u64 addr;
+	u32 *field;
+
+	if (!xdbcp->dbcc_base)
+		return;
+
+	xdbc_trace("%s:\n", str);
+
+	field = (u32 *)xdbcp->dbcc_base;
+	addr = xdbcp->dbcc_dma;
+	for (i = 0; i < XDBC_INFO_CONTEXT_SIZE;) {
+		xdbc_trace("@%016llx %08x %08x %08x %08x\n",
+			addr,
+			le32_to_cpu(field[i]),
+			le32_to_cpu(field[i + 1]),
+			le32_to_cpu(field[i + 2]),
+			le32_to_cpu(field[i + 3]));
+		addr += 16;
+		i += 4;
+	}
+}
+
+static void xdbc_dbg_dump_erst(char *str)
+{
+	int i;
+	u64 addr = xdbcp->erst_dma;
+	struct xdbc_erst_entry *entry;
+
+	if (!xdbcp->erst_base)
+		return;
+
+	xdbc_trace("%s\n", str);
+
+	for (i = 0; i < xdbcp->erst_size / sizeof(*entry); i++) {
+		entry = (struct xdbc_erst_entry *)xdbcp->erst_base + i;
+		xdbc_trace("@%016llx %08x %08x %08x %08x\n",
+			addr,
+			lower_32_bits(le64_to_cpu(entry->seg_addr)),
+			upper_32_bits(le64_to_cpu(entry->seg_addr)),
+			le32_to_cpu(entry->seg_size),
+			le32_to_cpu(entry->rsvd));
+		addr += sizeof(*entry);
+	}
+}
+
+static void xdbc_dbg_dump_segment(struct xdbc_segment *seg, char *str)
+{
+	int i;
+	u64 addr = seg->dma;
+	struct xdbc_trb *trb;
+
+	if (!seg->trbs)
+		return;
+
+	xdbc_trace("%s\n", str);
+
+	for (i = 0; i < XDBC_TRBS_PER_SEGMENT; i++) {
+		trb = &seg->trbs[i];
+		xdbc_trace("@%016llx %08x %08x %08x %08x\n", addr,
+			le32_to_cpu(trb->field[0]),
+			le32_to_cpu(trb->field[1]),
+			le32_to_cpu(trb->field[2]),
+			le32_to_cpu(trb->field[3]));
+		addr += sizeof(*trb);
+	}
+}
+
+static void xdbc_dbg_dump_string(char *str)
+{
+	u32 *string = (u32 *)xdbcp->string_base;
+	int i, max;
+
+	max = xdbcp->string_size / sizeof(u32);
+
+	xdbc_trace("%s\n", str);
+
+	for (i = 0; i < max; i += 4) {
+		xdbc_trace("@%016llx %08x %08x %08x %08x\n",
+			xdbcp->string_dma + i * 16,
+			le32_to_cpu(string[0]),
+			le32_to_cpu(string[1]),
+			le32_to_cpu(string[2]),
+			le32_to_cpu(string[3]));
+		string += 4;
+	}
+}
+
+static void xdbc_dbg_dump_data(char *str)
+{
+	xdbc_trace("XDBC data structure: %s\n", str);
+	xdbc_dbg_dump_erst("ERST:");
+	xdbc_dbg_dump_segment(&xdbcp->evt_seg, "Event Ring Segment:");
+	xdbc_dbg_dump_segment(&xdbcp->out_seg, "TXout Ring Segment:");
+	xdbc_dbg_dump_segment(&xdbcp->in_seg, "TXin Ring Segment:");
+	xdbc_dbg_dump_info_context("DBCC:");
+	xdbc_dbg_dump_string("String Descriptor:");
+}
+
+#else
+static inline void xdbc_trace(const char *fmt, ...) { }
+static inline void xdbc_dbg_dump_regs(char *str) { }
+static inline void xdbc_dbg_dump_data(char *str) { }
+#endif	/* DBC_DEBUG */
+
+/*
+ * FIXME: kernel provided delay interfaces, like usleep, isn't ready yet
+ *        at the time DbC gets initialized. Below implementation is only
+ *        for x86 platform. Need to reconsider this when porting it onto
+ *        other architectures.
+ */
+static inline void xdbc_udelay(int us)
+{
+	while (us-- > 0)
+		outb(0x1, 0x80);
+}
+
+static void __iomem *xdbc_map_pci_mmio(u32 bus,
+		u32 dev, u32 func, u8 bar, size_t *length)
+{
+	u32 val, sz;
+	u64 val64, sz64, mask64;
+	u8 byte;
+	unsigned long idx, max_idx;
+	void __iomem *base;
+
+	val = read_pci_config(bus, dev, func, bar);
+	write_pci_config(bus, dev, func, bar, ~0);
+	sz = read_pci_config(bus, dev, func, bar);
+	write_pci_config(bus, dev, func, bar, val);
+	if (val == 0xffffffff || sz == 0xffffffff) {
+		xdbc_trace("invalid mmio bar\n");
+		return NULL;
+	}
+
+	val64 = val & PCI_BASE_ADDRESS_MEM_MASK;
+	sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK;
+	mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK;
+
+	if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+			PCI_BASE_ADDRESS_MEM_TYPE_64) {
+		val = read_pci_config(bus, dev, func, bar + 4);
+		write_pci_config(bus, dev, func, bar + 4, ~0);
+		sz = read_pci_config(bus, dev, func, bar + 4);
+		write_pci_config(bus, dev, func, bar + 4, val);
+
+		val64 |= ((u64)val << 32);
+		sz64 |= ((u64)sz << 32);
+		mask64 |= ((u64)~0 << 32);
+	}
+
+	sz64 &= mask64;
+
+	if (sizeof(dma_addr_t) < 8 || !sz64) {
+		xdbc_trace("can't handle 64bit BAR\n");
+		return NULL;
+	}
+
+	sz64 = 1ULL << __ffs64(sz64);
+
+	if (sz64 > (FIX_XDBC_END - FIX_XDBC_BASE + 1) * PAGE_SIZE) {
+		xdbc_trace("mmio size beyond 64k not supported\n");
+		return NULL;
+	}
+
+	xdbc_trace("bar: base 0x%llx size 0x%llx offset %03x\n",
+			val64, sz64, bar);
+
+	/* check if the mem space is enabled */
+	byte = read_pci_config_byte(bus, dev, func, PCI_COMMAND);
+	if (!(byte & PCI_COMMAND_MEMORY)) {
+		byte  |= PCI_COMMAND_MEMORY;
+		write_pci_config_byte(bus, dev, func, PCI_COMMAND, byte);
+		xdbc_trace("mmio for xhci enabled\n");
+	}
+
+	/* 64k mmio will be fix-mapped */
+	max_idx = FIX_XDBC_END - FIX_XDBC_BASE;
+	for (idx = 0; idx <= max_idx; idx++)
+		set_fixmap_nocache(FIX_XDBC_BASE + idx,
+			(val64 & PAGE_MASK) + (max_idx - idx) * PAGE_SIZE);
+	base = (void __iomem *)__fix_to_virt(FIX_XDBC_END);
+	base += val64 & ~PAGE_MASK;
+
+	/* save in the state block */
+	xdbcp->bus = bus;
+	xdbcp->dev = dev;
+	xdbcp->func = func;
+	xdbcp->bar = bar;
+	xdbcp->xhci_base = base;
+	xdbcp->xhci_length = sz64;
+
+	if (length)
+		*length = sz64;
+
+	return base;
+}
+
+/*
+ * FIXME: The bootmem allocator isn't ready at the time when DbC gets
+ *        initialized. Below implementation reserves DMA memory blocks
+ *        in the kernel static data segment.
+ */
+static void *xdbc_get_page(dma_addr_t *dma_addr,
+		enum xdbc_page_type type)
+{
+	void *virt;
+	static char event_page[PAGE_SIZE] __aligned(PAGE_SIZE);
+	static char in_ring_page[PAGE_SIZE] __aligned(PAGE_SIZE);
+	static char out_ring_page[PAGE_SIZE] __aligned(PAGE_SIZE);
+	static char table_page[PAGE_SIZE] __aligned(PAGE_SIZE);
+
+	switch (type) {
+	case XDBC_PAGE_EVENT:
+		virt = (void *)event_page;
+		break;
+	case XDBC_PAGE_TXIN:
+		virt = (void *)in_ring_page;
+		break;
+	case XDBC_PAGE_TXOUT:
+		virt = (void *)out_ring_page;
+		break;
+	case XDBC_PAGE_TABLE:
+		virt = (void *)table_page;
+		break;
+	default:
+		return NULL;
+	}
+
+	memset(virt, 0, PAGE_SIZE);
+
+	if (dma_addr)
+		*dma_addr = (dma_addr_t)__pa(virt);
+
+	return virt;
+}
+
+typedef void (*xdbc_walk_excap_cb)(int cap_offset, void *data);
+
+/*
+ * xdbc_walk_excap:
+ *
+ * xHCI extended capability list walker.
+ *
+ * @bus - xHC PCI bus#
+ * @dev - xHC PCI dev#
+ * @func - xHC PCI function#
+ * @cap - capability ID
+ * @oneshot - return immediately once hit match
+ * @cb - call back
+ * @data - callback private data
+ *
+ * Return the last cap offset, otherwize 0.
+ */
+static u32 xdbc_walk_excap(u32 bus, u32 dev, u32 func, int cap,
+		bool oneshot, xdbc_walk_excap_cb cb, void *data)
+{
+	void __iomem *base;
+	int ext_cap_offset, retval = 0;
+	size_t len = 0;
+	u32 val;
+
+	if (xdbcp->xhci_base && xdbcp->xhci_length) {
+		if (xdbcp->bus != bus ||
+				xdbcp->dev != dev ||
+				xdbcp->func != func) {
+			xdbc_trace("only one DbC can be used\n");
+			return 0;
+		}
+
+		len = xdbcp->xhci_length;
+		base = xdbcp->xhci_base;
+	} else {
+		base = xdbc_map_pci_mmio(bus, dev, func,
+				PCI_BASE_ADDRESS_0, &len);
+		if (base == NULL)
+			return 0;
+	}
+
+	ext_cap_offset = xhci_find_next_cap_offset(base,
+			XHCI_HCC_PARAMS_OFFSET);
+	do {
+		if ((ext_cap_offset + sizeof(val)) >= len) {
+			xdbc_trace("malformed extended capability list\n");
+			break;
+		}
+
+		if (!ext_cap_offset)
+			break;
+
+		val = readl(base + ext_cap_offset);
+		if (XHCI_EXT_CAPS_ID(val) == cap) {
+			retval = ext_cap_offset;
+			if (cb)
+				cb(ext_cap_offset, data);
+			if (oneshot)
+				break;
+		}
+		ext_cap_offset = xhci_find_next_cap_offset(base,
+				ext_cap_offset);
+	} while (1);
+
+	return retval;
+}
+
+static u32 __init xdbc_find_dbgp(int xdbc_num,
+		u32 *rbus, u32 *rdev, u32 *rfunc)
+{
+	u32 bus, dev, func, class;
+	unsigned cap;
+
+	for (bus = 0; bus < XDBC_PCI_MAX_BUSES; bus++) {
+		for (dev = 0; dev < XDBC_PCI_MAX_DEVICES; dev++) {
+			for (func = 0; func < XDBC_PCI_MAX_FUNCTION; func++) {
+				class = read_pci_config(bus, dev, func,
+						PCI_CLASS_REVISION);
+				if ((class >> 8) != PCI_CLASS_SERIAL_USB_XHCI)
+					continue;
+
+				if (xdbc_num-- != 0)
+					continue;
+
+				cap = xdbc_walk_excap(bus, dev, func,
+						XHCI_EXT_CAPS_DEBUG,
+						true, NULL, NULL);
+				*rbus = bus;
+				*rdev = dev;
+				*rfunc = func;
+				return cap;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int handshake(void __iomem *ptr, u32 mask, u32 done,
+		int wait_usec, int delay_usec)
+{
+	u32	result;
+
+	do {
+		result = readl(ptr);
+		result &= mask;
+		if (result == done)
+			return 0;
+		xdbc_udelay(delay_usec);
+		wait_usec -= delay_usec;
+	} while (wait_usec > 0);
+
+	return -ETIMEDOUT;
+}
+
+static void __init xdbc_bios_handoff(void)
+{
+	int ext_cap_offset;
+	int timeout;
+	u32 val;
+
+	ext_cap_offset = xdbc_walk_excap(xdbcp->bus,
+					xdbcp->dev,
+					xdbcp->func,
+					XHCI_EXT_CAPS_LEGACY,
+					true, NULL, NULL);
+	val = readl(xdbcp->xhci_base + ext_cap_offset);
+
+	/* If the BIOS owns the HC, signal that the OS wants it, and wait */
+	if (val & XHCI_HC_BIOS_OWNED) {
+		writel(val | XHCI_HC_OS_OWNED,
+				xdbcp->xhci_base + ext_cap_offset);
+		timeout = handshake(xdbcp->xhci_base + ext_cap_offset,
+				XHCI_HC_BIOS_OWNED, 0, 5000, 10);
+
+		/* Assume a buggy BIOS and take HC ownership anyway */
+		if (timeout) {
+			xdbc_trace("xHCI BIOS handoff failed (BIOS bug ?)\n");
+			writel(val & ~XHCI_HC_BIOS_OWNED,
+					xdbcp->xhci_base + ext_cap_offset);
+		}
+	}
+
+	/* Disable any BIOS SMIs and clear all SMI events*/
+	val = readl(xdbcp->xhci_base + ext_cap_offset +
+			XHCI_LEGACY_CONTROL_OFFSET);
+	val &= XHCI_LEGACY_DISABLE_SMI;
+	val |= XHCI_LEGACY_SMI_EVENTS;
+	writel(val, xdbcp->xhci_base + ext_cap_offset +
+			XHCI_LEGACY_CONTROL_OFFSET);
+}
+
+/*
+ * xdbc_alloc_ring: allocate physical memory for a ring
+ */
+static int xdbc_alloc_ring(struct xdbc_segment *seg,
+		struct xdbc_ring *ring,
+		enum xdbc_page_type type)
+{
+	struct xdbc_trb *link_trb;
+
+	seg->trbs = xdbc_get_page(&seg->dma, type);
+	if (!seg->trbs)
+		return -ENOMEM;
+
+	ring->segment = seg;
+	ring->enqueue = seg->trbs;
+	ring->dequeue = seg->trbs;
+	ring->cycle_state = 1;
+
+	if (type == XDBC_PAGE_TXIN || type == XDBC_PAGE_TXOUT) {
+		link_trb = &seg->trbs[XDBC_TRBS_PER_SEGMENT - 1];
+		link_trb->field[0] = cpu_to_le32(lower_32_bits(seg->dma));
+		link_trb->field[1] = cpu_to_le32(upper_32_bits(seg->dma));
+		link_trb->field[3] = cpu_to_le32(TRB_TYPE(TRB_LINK)) |
+				cpu_to_le32(LINK_TOGGLE);
+	}
+
+	return 0;
+}
+
+static inline void xdbc_put_utf16(u16 *s, const char *c, size_t size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		s[i] = cpu_to_le16(c[i]);
+}
+
+static int xdbc_mem_init(void)
+{
+	struct xdbc_erst_entry *entry;
+	struct xdbc_strings *strings;
+	struct xdbc_context *context;
+	struct xdbc_ep_context *ep_in, *ep_out;
+	struct usb_string_descriptor *s_desc;
+	unsigned int max_burst;
+	u32 string_length;
+	int ret, index = 0;
+	u32 dev_info;
+
+	/* allocate table page */
+	xdbcp->table_base = xdbc_get_page(&xdbcp->table_dma,
+			XDBC_PAGE_TABLE);
+	if (!xdbcp->table_base) {
+		xdbc_trace("falied to alloc table page\n");
+		return -ENOMEM;
+	}
+
+	/* allocate and initialize event ring */
+	ret = xdbc_alloc_ring(&xdbcp->evt_seg, &xdbcp->evt_ring,
+			XDBC_PAGE_EVENT);
+	if (ret < 0) {
+		xdbc_trace("failed to alloc event ring\n");
+		return ret;
+	}
+
+	/* allocate event ring segment table */
+	xdbcp->erst_size = 16;
+	xdbcp->erst_base = xdbcp->table_base +
+			index * XDBC_TABLE_ENTRY_SIZE;
+	xdbcp->erst_dma = xdbcp->table_dma +
+			index * XDBC_TABLE_ENTRY_SIZE;
+	index += XDBC_ERST_ENTRY_NUM;
+
+	/* Initialize Event Ring Segment Table */
+	entry = (struct xdbc_erst_entry *)xdbcp->erst_base;
+	entry->seg_addr = cpu_to_le64(xdbcp->evt_seg.dma);
+	entry->seg_size = cpu_to_le32(XDBC_TRBS_PER_SEGMENT);
+	entry->rsvd = 0;
+
+	/* Initialize ERST registers */
+	writel(1, &xdbcp->xdbc_reg->ersts);
+	xdbc_write64(xdbcp->erst_dma, &xdbcp->xdbc_reg->erstba);
+	xdbc_write64(xdbcp->evt_seg.dma, &xdbcp->xdbc_reg->erdp);
+
+	/* debug capability contexts */
+	BUILD_BUG_ON(sizeof(struct xdbc_info_context) != 64);
+	BUILD_BUG_ON(sizeof(struct xdbc_ep_context) != 64);
+	BUILD_BUG_ON(sizeof(struct xdbc_context) != 64 * 3);
+
+	xdbcp->dbcc_size = 64 * 3;
+	xdbcp->dbcc_base = xdbcp->table_base +
+			index * XDBC_TABLE_ENTRY_SIZE;
+	xdbcp->dbcc_dma = xdbcp->table_dma +
+			index * XDBC_TABLE_ENTRY_SIZE;
+	index += XDBC_DBCC_ENTRY_NUM;
+
+	/* IN/OUT endpoint transfer ring */
+	ret = xdbc_alloc_ring(&xdbcp->in_seg, &xdbcp->in_ring,
+			XDBC_PAGE_TXIN);
+	if (ret < 0) {
+		xdbc_trace("failed to alloc IN transfer ring\n");
+		return ret;
+	}
+
+	ret = xdbc_alloc_ring(&xdbcp->out_seg, &xdbcp->out_ring,
+			XDBC_PAGE_TXOUT);
+	if (ret < 0) {
+		xdbc_trace("failed to alloc OUT transfer ring\n");
+		return ret;
+	}
+
+	/* strings */
+	xdbcp->string_size = sizeof(struct xdbc_strings);
+	xdbcp->string_base = xdbcp->table_base +
+			index * XDBC_TABLE_ENTRY_SIZE;
+	xdbcp->string_dma = xdbcp->table_dma +
+			index * XDBC_TABLE_ENTRY_SIZE;
+	index += XDBC_STRING_ENTRY_NUM;
+
+	strings = (struct xdbc_strings *)xdbcp->string_base;
+
+	/* serial string */
+	s_desc = (struct usb_string_descriptor *)strings->serial;
+	s_desc->bLength = (strlen(XDBC_STRING_SERIAL) + 1) * 2;
+	s_desc->bDescriptorType = USB_DT_STRING;
+	xdbc_put_utf16(s_desc->wData, XDBC_STRING_SERIAL,
+			strlen(XDBC_STRING_SERIAL));
+
+	string_length = s_desc->bLength;
+	string_length <<= 8;
+
+	/* product string */
+	s_desc = (struct usb_string_descriptor *)strings->product;
+	s_desc->bLength = (strlen(XDBC_STRING_PRODUCT) + 1) * 2;
+	s_desc->bDescriptorType = USB_DT_STRING;
+	xdbc_put_utf16(s_desc->wData, XDBC_STRING_PRODUCT,
+			strlen(XDBC_STRING_PRODUCT));
+
+	string_length += s_desc->bLength;
+	string_length <<= 8;
+
+	/* manufacture string */
+	s_desc = (struct usb_string_descriptor *)strings->manufacture;
+	s_desc->bLength = (strlen(XDBC_STRING_MANUFACTURE) + 1) * 2;
+	s_desc->bDescriptorType = USB_DT_STRING;
+	xdbc_put_utf16(s_desc->wData, XDBC_STRING_MANUFACTURE,
+			strlen(XDBC_STRING_MANUFACTURE));
+
+	string_length += s_desc->bLength;
+	string_length <<= 8;
+
+	/* string 0 */
+	strings->string0[0] = 4;
+	strings->string0[1] = USB_DT_STRING;
+	strings->string0[2] = 0x09;
+	strings->string0[3] = 0x04;
+
+	string_length += 4;
+
+	/* populate the contexts */
+	context = (struct xdbc_context *)xdbcp->dbcc_base;
+	context->info.string0 = cpu_to_le64(xdbcp->string_dma);
+	context->info.manufacture = cpu_to_le64(xdbcp->string_dma +
+			XDBC_MAX_STRING_LENGTH);
+	context->info.product = cpu_to_le64(xdbcp->string_dma +
+			XDBC_MAX_STRING_LENGTH * 2);
+	context->info.serial = cpu_to_le64(xdbcp->string_dma +
+			XDBC_MAX_STRING_LENGTH * 3);
+	context->info.length = cpu_to_le32(string_length);
+
+	max_burst = DEBUG_MAX_BURST(readl(&xdbcp->xdbc_reg->control));
+	ep_out = (struct xdbc_ep_context *)&context->out;
+	ep_out->ep_info1 = 0;
+	ep_out->ep_info2 = cpu_to_le32(EP_TYPE(BULK_OUT_EP) |
+			MAX_PACKET(1024) | MAX_BURST(max_burst));
+	ep_out->deq = cpu_to_le64(xdbcp->out_seg.dma |
+			xdbcp->out_ring.cycle_state);
+
+	ep_in = (struct xdbc_ep_context *)&context->in;
+	ep_in->ep_info1 = 0;
+	ep_in->ep_info2 = cpu_to_le32(EP_TYPE(BULK_OUT_EP) |
+			MAX_PACKET(1024) | MAX_BURST(max_burst));
+	ep_in->deq = cpu_to_le64(xdbcp->in_seg.dma |
+			xdbcp->in_ring.cycle_state);
+
+	/* write DbC context pointer register */
+	xdbc_write64(xdbcp->dbcc_dma, &xdbcp->xdbc_reg->dccp);
+
+	/* device descriptor info registers */
+	dev_info = cpu_to_le32((XDBC_VENDOR_ID << 16) | XDBC_PROTOCOL);
+	writel(dev_info, &xdbcp->xdbc_reg->devinfo1);
+	dev_info = cpu_to_le32((XDBC_DEVICE_REV << 16) | XDBC_PRODUCT_ID);
+	writel(dev_info, &xdbcp->xdbc_reg->devinfo2);
+
+	return 0;
+}
+
+/*
+ * xdbc_start: start DbC
+ *
+ * Set DbC enable bit and wait until DbC run bit being set or timed out.
+ */
+static int xdbc_start(void)
+{
+	u32 ctrl, status;
+
+	ctrl = readl(&xdbcp->xdbc_reg->control);
+	writel(ctrl | CTRL_DCE | CTRL_LSE, &xdbcp->xdbc_reg->control);
+
+	if (handshake(&xdbcp->xdbc_reg->control, CTRL_DCE,
+			CTRL_DCE, 100000, 100) < 0) {
+		xdbc_trace("falied to initialize hardware\n");
+		return -ENODEV;
+	}
+
+	/* wait for port connection */
+	if (handshake(&xdbcp->xdbc_reg->portsc, PORTSC_CCS,
+			PORTSC_CCS, 5000000, 100) < 0) {
+		xdbc_trace("waiting for connection timed out\n");
+		return -ETIMEDOUT;
+	}
+	xdbc_trace("port connection detected\n");
+
+	/* wait for debug device to be configured */
+	if (handshake(&xdbcp->xdbc_reg->control, CTRL_DCR,
+			CTRL_DCR, 5000000, 100) < 0) {
+		xdbc_trace("waiting for device configuration timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	/* port should have a valid port# */
+	status = readl(&xdbcp->xdbc_reg->status);
+	if (!DCST_DPN(status)) {
+		xdbc_trace("invalid root hub port number\n");
+		return -ENODEV;
+	}
+
+	xdbc_trace("root hub port number %d\n", DCST_DPN(status));
+
+	xdbc_trace("DbC is running now, control 0x%08x\n",
+			readl(&xdbcp->xdbc_reg->control));
+
+	return 0;
+}
+
+static int xdbc_setup(void)
+{
+	int ret;
+
+	writel(0, &xdbcp->xdbc_reg->control);
+	if (handshake(&xdbcp->xdbc_reg->control, CTRL_DCE,
+			0, 100000, 100) < 0) {
+		xdbc_trace("falied to initialize hardware\n");
+		return -ETIMEDOUT;
+	}
+
+	/* allocate and initialize all memory data structures */
+	ret = xdbc_mem_init();
+	if (ret < 0) {
+		xdbc_trace("failed to initialize memory\n");
+		return ret;
+	}
+
+	/*
+	 * Memory barrier to ensure hardware sees the bits
+	 * setting above.
+	 */
+	mmiowb();
+
+	/* dump registers and data structures */
+	xdbc_dbg_dump_regs("hardware setup completed");
+	xdbc_dbg_dump_data("hardware setup completed");
+
+	ret = xdbc_start();
+	if (ret < 0) {
+		xdbc_trace("failed to start DbC, cable connected?\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int __init early_xdbc_init(char *s)
+{
+	u32 bus = 0, dev = 0, func = 0;
+	unsigned long dbgp_num = 0;
+	u32 offset;
+	int ret;
+
+	if (!early_pci_allowed())
+		return -EPERM;
+
+	/* FIXME: early printk "keep" option will be supported later */
+	if (strstr(s, "keep"))
+		return -EPERM;
+
+	if (xdbcp->xdbc_reg)
+		return 0;
+
+	if (*s && kstrtoul(s, 0, &dbgp_num))
+		dbgp_num = 0;
+
+	xdbc_trace("dbgp_num: %lu\n", dbgp_num);
+
+	offset = xdbc_find_dbgp(dbgp_num, &bus, &dev, &func);
+	if (!offset)
+		return -ENODEV;
+
+	xdbc_trace("Found xHCI debug capability on %02x:%02x.%1x\n",
+			bus, dev, func);
+
+	if (!xdbcp->xhci_base)
+		return -EINVAL;
+
+	xdbcp->xdbc_reg = (struct xdbc_regs __iomem *)
+			(xdbcp->xhci_base + offset);
+	xdbc_dbg_dump_regs("debug capability located");
+
+	/* hand over the owner of host from BIOS */
+	xdbc_bios_handoff();
+
+	ret = xdbc_setup();
+	if (ret < 0) {
+		pr_notice("failed to setup xHCI DbC connection\n");
+		xdbcp->xhci_base = NULL;
+		xdbcp->xdbc_reg = NULL;
+		return ret;
+	}
+
+	return 0;
+}
diff --git a/include/linux/usb/xhci-dbc.h b/include/linux/usb/xhci-dbc.h
new file mode 100644
index 0000000..153fb87
--- /dev/null
+++ b/include/linux/usb/xhci-dbc.h
@@ -0,0 +1,187 @@
+/*
+ * xHCI debug capability driver
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * Author: Lu Baolu <baolu.lu@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_XHCI_DBC_H
+#define __LINUX_XHCI_DBC_H
+
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+
+/**
+ * struct xdbc_regs - xHCI Debug Capability Register interface.
+ */
+struct xdbc_regs {
+	__le32	capability;
+	__le32	doorbell;
+	__le32	ersts;		/* Event Ring Segment Table Size*/
+	__le32	rvd0;		/* 0c~0f reserved bits */
+	__le64	erstba;		/* Event Ring Segment Table Base Address */
+	__le64	erdp;		/* Event Ring Dequeue Pointer */
+	__le32	control;
+#define	DEBUG_MAX_BURST(p)	(((p) >> 16) & 0xff)
+#define	CTRL_DCR		(1 << 0)	/* DbC Run */
+#define	CTRL_PED		(1 << 1)	/* Port Enable/Disable */
+#define	CTRL_HOT		(1 << 2)	/* Halt Out TR */
+#define	CTRL_HIT		(1 << 3)	/* Halt In TR */
+#define	CTRL_DRC		(1 << 4)	/* DbC run change */
+#define	CTRL_DCE		(1 << 31)	/* DbC enable */
+#define	CTRL_LSE		(1 << 1)
+	__le32	status;
+#define	DCST_DPN(p)		(((p) >> 24) & 0xff)
+	__le32	portsc;		/* Port status and control */
+#define	PORTSC_CCS		(1 << 0)
+#define	PORTSC_CSC		(1 << 17)
+#define	PORTSC_PRC		(1 << 21)
+#define	PORTSC_PLC		(1 << 22)
+#define	PORTSC_CEC		(1 << 23)
+	__le32	rvd1;		/* 2b~28 reserved bits */
+	__le64	dccp;		/* Debug Capability Context Pointer */
+	__le32	devinfo1;	/* Device Descriptor Info Register 1 */
+	__le32	devinfo2;	/* Device Descriptor Info Register 2 */
+};
+
+/*
+ * xHCI Debug Capability data structures
+ */
+struct xdbc_trb {
+	__le32 field[4];
+};
+
+struct xdbc_erst_entry {
+	__le64	seg_addr;
+	__le32	seg_size;
+	__le32	rsvd;
+};
+
+struct xdbc_info_context {
+	__le64	string0;
+	__le64	manufacture;
+	__le64	product;
+	__le64	serial;
+	__le32	length;
+	__le32	rsvdz[7];
+};
+
+struct xdbc_ep_context {
+	__le32	ep_info1;
+	__le32	ep_info2;
+	__le64	deq;
+	__le32	tx_info;
+	__le32	rsvd0[11];
+};
+
+struct xdbc_context {
+	struct xdbc_info_context	info;
+	struct xdbc_ep_context		out;
+	struct xdbc_ep_context		in;
+};
+
+#define	XDBC_INFO_CONTEXT_SIZE		48
+
+#define	XDBC_MAX_STRING_LENGTH		64
+#define	XDBC_STRING_MANUFACTURE		"Linux"
+#define	XDBC_STRING_PRODUCT		"Remote GDB"
+#define	XDBC_STRING_SERIAL		"0001"
+struct xdbc_strings {
+	char	string0[XDBC_MAX_STRING_LENGTH];
+	char	manufacture[XDBC_MAX_STRING_LENGTH];
+	char	product[XDBC_MAX_STRING_LENGTH];
+	char	serial[XDBC_MAX_STRING_LENGTH];
+};
+
+/*
+ * software state structure
+ */
+struct xdbc_segment {
+	struct xdbc_trb		*trbs;
+	dma_addr_t		dma;
+};
+
+#define	XDBC_TRBS_PER_SEGMENT	256
+
+struct xdbc_ring {
+	struct xdbc_segment	*segment;
+	struct xdbc_trb		*enqueue;
+	struct xdbc_trb		*dequeue;
+	u32			cycle_state;
+};
+
+enum xdbc_page_type {
+	XDBC_PAGE_EVENT,
+	XDBC_PAGE_TXIN,
+	XDBC_PAGE_TXOUT,
+	XDBC_PAGE_TABLE,
+};
+
+struct xdbc_state {
+	/* pci device info*/
+	u32		bus;
+	u32		dev;
+	u32		func;
+	u8		bar;
+	void __iomem	*xhci_base;
+	size_t		xhci_length;
+#define	XDBC_PCI_MAX_BUSES		256
+#define	XDBC_PCI_MAX_DEVICES		32
+#define	XDBC_PCI_MAX_FUNCTION		8
+
+	/* DbC register base */
+	struct		xdbc_regs __iomem *xdbc_reg;
+
+	/* DbC table page */
+	dma_addr_t	table_dma;
+	void		*table_base;
+
+#define	XDBC_TABLE_ENTRY_SIZE		64
+#define	XDBC_ERST_ENTRY_NUM		1
+#define	XDBC_DBCC_ENTRY_NUM		3
+#define	XDBC_STRING_ENTRY_NUM		4
+
+	/* event ring segment table */
+	dma_addr_t	erst_dma;
+	size_t		erst_size;
+	void		*erst_base;
+
+	/* event ring segments */
+	struct xdbc_ring	evt_ring;
+	struct xdbc_segment	evt_seg;
+
+	/* debug capability contexts */
+	dma_addr_t	dbcc_dma;
+	size_t		dbcc_size;
+	void		*dbcc_base;
+
+	/* descriptor strings */
+	dma_addr_t	string_dma;
+	size_t		string_size;
+	void		*string_base;
+
+	/* bulk OUT endpoint */
+	struct xdbc_ring	out_ring;
+	struct xdbc_segment	out_seg;
+
+	/* bulk IN endpoint */
+	struct xdbc_ring	in_ring;
+	struct xdbc_segment	in_seg;
+};
+
+#define	XDBC_MAX_PACKET		1024
+
+/* door bell target */
+#define	OUT_EP_DOORBELL		0
+#define	IN_EP_DOORBELL		1
+#define	DOOR_BELL_TARGET(p)	(((p) & 0xff) << 8)
+
+#define	xdbc_read64(regs)	xhci_read_64(NULL, (regs))
+#define	xdbc_write64(val, regs)	xhci_write_64(NULL, (val), (regs))
+
+#endif /* __LINUX_XHCI_DBC_H */
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web