Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aeb9dd1d authored by Lu Baolu's avatar Lu Baolu Committed by Ingo Molnar
Browse files

usb/early: Add driver for xhci debug capability



XHCI debug capability (DbC) is an optional but standalone
functionality provided by an xHCI host controller. Software
learns this capability by walking through the extended
capability list of the host. XHCI specification describes
DbC in section 7.6.

This patch introduces the code to probe and initialize the
debug capability hardware during early boot. With hardware
initialized, the debug target (system on which this code is
running) will present a debug device through the debug port
(normally the first USB3 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. The DbC functionality is
independent of the xHCI host. There isn't any precondition
from the xHCI host side for the DbC to work.

One use for this feature is kernel debugging, for example
when your machine crashes very early before the regular
console code is initialized. Other uses include simpler,
lockless logging instead of a full-blown printk console
driver and klogd.

Signed-off-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mathias Nyman <mathias.nyman@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-usb@vger.kernel.org
Link: http://lkml.kernel.org/r/1490083293-3792-3-git-send-email-baolu.lu@linux.intel.com


[ Small fix to the Kconfig help text. ]
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent dd759d93
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -5,6 +5,9 @@ config TRACE_IRQFLAGS_SUPPORT

source "lib/Kconfig.debug"

config EARLY_PRINTK_USB
	bool

config X86_VERBOSE_BOOTUP
	bool "Enable verbose x86 bootup info messages"
	default y
@@ -23,19 +26,20 @@ config EARLY_PRINTK
	  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,
	  with klogd/syslogd or the X server. You should normally say N here,
	  unless you want to debug such a crash.

config EARLY_PRINTK_DBGP
	bool "Early printk via EHCI debug port"
	depends on EARLY_PRINTK && PCI
	select EARLY_PRINTK_USB
	---help---
	  Write kernel log output directly into the EHCI 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,
	  with klogd/syslogd or the X server. You should normally say N here,
	  unless you want to debug such a crash. You need usb debug device.

config EARLY_PRINTK_EFI
@@ -48,6 +52,25 @@ 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_USB_XDBC
	bool "Early printk via the xHCI debug port"
	depends on EARLY_PRINTK && PCI
	select EARLY_PRINTK_USB
	---help---
	  Write kernel log output directly into the xHCI debug port.

	  One use for this feature is kernel debugging, for example when your
	  machine crashes very early before the regular console code is
	  initialized. Other uses include simpler, lockless logging instead of
	  a full-blown printk console driver + klogd.

	  For normal production environments this is normally not recommended,
	  because it doesn't feed events into klogd/syslogd and doesn't try to
	  print anything on the screen.

	  You should normally say N here, unless you want to debug early
	  crashes or need a very simple printk logging facility.

config X86_PTDUMP_CORE
	def_bool n

+1 −1
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL)	+= serial/

obj-$(CONFIG_USB)		+= misc/
obj-$(CONFIG_EARLY_PRINTK_DBGP)	+= early/
obj-$(CONFIG_EARLY_PRINTK_USB)	+= early/

obj-$(CONFIG_USB_ATM)		+= atm/
obj-$(CONFIG_USB_SPEEDTOUCH)	+= atm/
+1 −0
Original line number Diff line number Diff line
@@ -3,3 +3,4 @@
#

obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
obj-$(CONFIG_EARLY_PRINTK_USB_XDBC) += xhci-dbc.o
+1014 −0

File added.

Preview size limit exceeded, changes collapsed.

+211 −0
Original line number Diff line number Diff line
/*
 * xhci-dbc.h - xHCI debug capability early driver
 *
 * Copyright (C) 2016 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>

/*
 * xHCI Debug Capability Register interfaces:
 */
struct xdbc_regs {
	__le32	capability;
	__le32	doorbell;
	__le32	ersts;		/* Event Ring Segment Table Size*/
	__le32	__reserved_0;	/* 0c~0f reserved bits */
	__le64	erstba;		/* Event Ring Segment Table Base Address */
	__le64	erdp;		/* Event Ring Dequeue Pointer */
	__le32	control;
	__le32	status;
	__le32	portsc;		/* Port status and control */
	__le32	__reserved_1;	/* 2b~28 reserved bits */
	__le64	dccp;		/* Debug Capability Context Pointer */
	__le32	devinfo1;	/* Device Descriptor Info Register 1 */
	__le32	devinfo2;	/* Device Descriptor Info Register 2 */
};

#define DEBUG_MAX_BURST(p)	(((p) >> 16) & 0xff)

#define CTRL_DBC_RUN		BIT(0)
#define CTRL_PORT_ENABLE	BIT(1)
#define CTRL_HALT_OUT_TR	BIT(2)
#define CTRL_HALT_IN_TR		BIT(3)
#define CTRL_DBC_RUN_CHANGE	BIT(4)
#define CTRL_DBC_ENABLE		BIT(31)

#define DCST_DEBUG_PORT(p)	(((p) >> 24) & 0xff)

#define PORTSC_CONN_STATUS	BIT(0)
#define PORTSC_CONN_CHANGE	BIT(17)
#define PORTSC_RESET_CHANGE	BIT(21)
#define PORTSC_LINK_CHANGE	BIT(22)
#define PORTSC_CONFIG_CHANGE	BIT(23)

/*
 * xHCI Debug Capability data structures:
 */
struct xdbc_trb {
	__le32 field[4];
};

struct xdbc_erst_entry {
	__le64	seg_addr;
	__le32	seg_size;
	__le32	__reserved_0;
};

struct xdbc_info_context {
	__le64	string0;
	__le64	manufacturer;
	__le64	product;
	__le64	serial;
	__le32	length;
	__le32	__reserved_0[7];
};

struct xdbc_ep_context {
	__le32	ep_info1;
	__le32	ep_info2;
	__le64	deq;
	__le32	tx_info;
	__le32	__reserved_0[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_MANUFACTURER	"Linux"
#define XDBC_STRING_PRODUCT		"Remote GDB"
#define XDBC_STRING_SERIAL		"0001"

struct xdbc_strings {
	char	string0[XDBC_MAX_STRING_LENGTH];
	char	manufacturer[XDBC_MAX_STRING_LENGTH];
	char	product[XDBC_MAX_STRING_LENGTH];
	char	serial[XDBC_MAX_STRING_LENGTH];
};

#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 */

/*
 * xHCI Debug Capability software state structures:
 */
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;
};

#define XDBC_EPID_OUT		2
#define XDBC_EPID_IN		3

struct xdbc_state {
	u16			vendor;
	u16			device;
	u32			bus;
	u32			dev;
	u32			func;
	void __iomem		*xhci_base;
	u64			xhci_start;
	size_t			xhci_length;
	int			port_number;

	/* DbC register base */
	struct xdbc_regs __iomem *xdbc_reg;

	/* DbC table page */
	dma_addr_t		table_dma;
	void			*table_base;

	/* 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;
	void			*out_buf;
	dma_addr_t		out_dma;

	/* bulk IN endpoint */
	struct xdbc_ring	in_ring;
	struct xdbc_segment	in_seg;
	void			*in_buf;
	dma_addr_t		in_dma;

	u32			flags;

	/* spinlock for early_xdbc_write() reentrancy */
	raw_spinlock_t		lock;
};

#define XDBC_PCI_MAX_BUSES	256
#define XDBC_PCI_MAX_DEVICES	32
#define XDBC_PCI_MAX_FUNCTION	8

#define XDBC_TABLE_ENTRY_SIZE	64
#define XDBC_ERST_ENTRY_NUM	1
#define XDBC_DBCC_ENTRY_NUM	3
#define XDBC_STRING_ENTRY_NUM	4

/* Bits definitions for xdbc_state.flags: */
#define XDBC_FLAGS_INITIALIZED	BIT(0)
#define XDBC_FLAGS_IN_STALL	BIT(1)
#define XDBC_FLAGS_OUT_STALL	BIT(2)
#define XDBC_FLAGS_IN_PROCESS	BIT(3)
#define XDBC_FLAGS_OUT_PROCESS	BIT(4)
#define XDBC_FLAGS_CONFIGURED	BIT(5)

#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 */
Loading