Skip to contentSkip to conversation

usb: early: add support for early printk through USB3 debug port

PATCH Superseded Lu Baolu 2 participants 7 messages Jan 22, 2017 – Jan 24, 2017

Subsystems (4)

v6 of 8 Superseded Latest is v8 →

lore
Share & tools
lore

Lu Baolu

author
#0 lore raw

v6 cover usb: early: add support for early printk through USB3 debug port

xHCI debug capability (DbC) is an optional but standalone functionality provided by an xHCI host controller. With DbC hardware initialized, the system will present a debug device through the USB3 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 xHCI host. There isn't any precondition from xHCI host side for DbC to work.

This patch set adds support for early printk functionality through a USB3 debug port by 1) initializing and enabling the DbC hardware during early boot; 2) registering a boot console to the system so that early printk messages can go through the USB3 debug port. It also includes some lines of changes in usb_debug driver so that it can be bound when a USB3 debug device is enumerated.

---
Change log:
v5->v6:
- rebase the patches on top of the latest 4.10-rc4
- run successfully in a 32-bit kernel
- [PATCH 1/4]
- remove ugly linebreaks to make code more readable
- rename config names to make them consistency
- move sleep-able ioremap() out of the lock area
- rename reserved fields of register structures
- make the vertical tabulation of struct fields consistent
- [PATCH 2/4]
- remove "#ifdef" in the generic code by creating proper wrappers in header file
- [PATCH 3/4]
- refine the title and commit message
- [PATCH 4/4]
- fix several typos and grammar errors in the document

v4->v5:
- add raw_spin_lock to make xdbc_bulk_write() reentrant.

v3->v4:
- Rename the document with .dst suffix.
- Add the list of hardware that has been succesfuly tested on in the document.

v2->v3:
- Removed spinlock usage.
- Removed work queue usage.
- Refined the user guide document.

v1->v2:
- Refactor the duplicate code in xdbc_early_start() and xdbc_handle_external_reset().
- Free resources when hardware not used any more.
- Refine the user guide document.

Lu Baolu (4):
usb: dbc: early driver for xhci debug capability
x86: add support for earlyprintk via USB3 debug port
usb: serial: add dbc debug device support to usb_debug
usb: doc: add document for USB3 debug port usage

 Documentation/admin-guide/kernel-parameters.txt |    1 +
 Documentation/usb/usb3-debug-port.rst           |   98 +++
 arch/x86/Kconfig.debug                          |   17 +
 arch/x86/kernel/early_printk.c                  |    5 +
 arch/x86/kernel/setup.c                         |    4 +
 drivers/usb/Kconfig                             |    3 +
 drivers/usb/Makefile                            |    2 +-
 drivers/usb/early/Makefile                      |    1 +
 drivers/usb/early/xhci-dbc.c                    | 1027 +++++++++++++++++++++++
 drivers/usb/early/xhci-dbc.h                    |  205 +++++
 drivers/usb/serial/usb_debug.c                  |   28 +-
 include/linux/usb/xhci-dbgp.h                   |   29 +
 12 files changed, 1416 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/usb/usb3-debug-port.rst
 create mode 100644 drivers/usb/early/xhci-dbc.c
 create mode 100644 drivers/usb/early/xhci-dbc.h
 create mode 100644 include/linux/usb/xhci-dbgp.h
Signature · 1 line
2.1.4
author
#1 lore raw

PATCH v6 1/4 usb: dbc: early 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 xHCI host. There isn't any precondition from xHCI host side for DbC to work.

This patch also includes bulk out and bulk in interfaces. These interfaces could be used to implement early printk bootconsole or hook to various system debuggers.

Cc Mathias Nyman <[email protected]>
---
 arch/x86/Kconfig.debug        |   17 +
 drivers/usb/Kconfig           |    3 +
 drivers/usb/Makefile          |    2 +-
 drivers/usb/early/Makefile    |    1 +
 drivers/usb/early/xhci-dbc.c  | 1027 +++++++++++++++++++++++++++++++++++++++++
 drivers/usb/early/xhci-dbc.h  |  205 ++++++++
 include/linux/usb/xhci-dbgp.h |   29 ++
 7 files changed, 1283 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/early/xhci-dbc.c
 create mode 100644 drivers/usb/early/xhci-dbc.h
 create mode 100644 include/linux/usb/xhci-dbgp.h
arch/x86/Kconfig.debug +17 -0
index 67eec55..ab0178f 100644
@@ -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
@@ -29,6 +32,7 @@ config EARLY_PRINTK
 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.
 
@@ -48,6 +52,19 @@ 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 xHCI debug port"
+	depends on EARLY_PRINTK && PCI
+	select EARLY_PRINTK_USB
+	---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_CORE
 	def_bool n
 
drivers/usb/Kconfig +3 -0
index fbe493d..9313fff 100644
@@ -19,6 +19,9 @@ config USB_EHCI_BIG_ENDIAN_MMIO
 config USB_EHCI_BIG_ENDIAN_DESC
 	bool
 
+config USB_EARLY_PRINTK
+	bool
+
 menuconfig USB_SUPPORT
 	bool "USB support"
 	depends on HAS_IOMEM
drivers/usb/Makefile +1 -1
index 7791af6..53d1356 100644
@@ -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/
drivers/usb/early/Makefile +1 -0
index 24bbe51..fcde228 100644
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
+obj-$(CONFIG_EARLY_PRINTK_USB_XDBC) += xhci-dbc.o
drivers/usb/early/xhci-dbc.c new file +1027 -0

1,027 lines not on this page · raw message

drivers/usb/early/xhci-dbc.h new file +205 -0

205 lines not on this page · raw message

include/linux/usb/xhci-dbgp.h new file +29 -0
new file mode 100644
index 0000000..80c1cca
@@ -0,0 +1,29 @@
+/*
+ * Standalone xHCI debug capability driver
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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_DBGP_H
+#define __LINUX_XHCI_DBGP_H
+
+#ifdef CONFIG_EARLY_PRINTK_USB_XDBC
+int __init early_xdbc_parse_parameter(char *s);
+int __init early_xdbc_setup_hardware(void);
+void __init early_xdbc_register_console(void);
+#else
+static inline int __init early_xdbc_setup_hardware(void)
+{
+	return -ENODEV;
+}
+static inline void __init early_xdbc_register_console(void)
+{
+}
+#endif /* CONFIG_EARLY_PRINTK_USB_XDBC */
+#endif /* __LINUX_XHCI_DBGP_H */
Signature · 1 line
2.1.4
#2 lore raw

Re: [PATCH v6 1/4] usb: dbc: early driver for xhci debug capability

Quoted 6 lines · Lu Baolu

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.

Quoted 10 lines

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 xHCI host. There isn't any precondition from xHCI host side for DbC to work.

s/xHCI host/the xHCI host

Quoted 3 lines

This patch also includes bulk out and bulk in interfaces. These interfaces could be used to implement early printk bootconsole or hook to various system debuggers.

s/out/output
s/in/input

arch/x86/Kconfig.debug config EARLY_PRINTK_EFI · line 56

Quoted 2 lines
arch/x86/Kconfig.debug +2 -0
+config EARLY_PRINTK_USB_XDBC
+	bool "Early printk via xHCI debug port"

s/xHCI/the xHCI

I remarked on this in my first review as well - mind checking the whole series for uses of 'xHCI'?

Quoted 106 lines
arch/x86/Kconfig.debug +11 -0
+	depends on EARLY_PRINTK && PCI
+	select EARLY_PRINTK_USB
+	---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_CORE
 	def_bool n
drivers/usb/Kconfig +3 -0
index fbe493d..9313fff 100644
@@ -19,6 +19,9 @@ config USB_EHCI_BIG_ENDIAN_MMIO
 config USB_EHCI_BIG_ENDIAN_DESC
 	bool
 
+config USB_EARLY_PRINTK
+	bool
+
 menuconfig USB_SUPPORT
 	bool "USB support"
 	depends on HAS_IOMEM
drivers/usb/Makefile +1 -1
index 7791af6..53d1356 100644
@@ -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/
drivers/usb/early/Makefile +1 -0
index 24bbe51..fcde228 100644
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
+obj-$(CONFIG_EARLY_PRINTK_USB_XDBC) += xhci-dbc.o
drivers/usb/early/xhci-dbc.c new file +50 -0
new file mode 100644
index 0000000..72480c4
@@ -0,0 +1,1027 @@
+/**
+ * xhci-dbc.c - xHCI debug capability early driver
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ":%s: " fmt, __func__
+
+#include <linux/console.h>
+#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/module.h>
+#include <linux/delay.h>
+
+#include "../host/xhci.h"
+#include "xhci-dbc.h"
+
+static struct xdbc_state xdbc;
+static int early_console_keep;
+
+#ifdef XDBC_TRACE
+#define	xdbc_trace	trace_printk
+#else
+static inline void xdbc_trace(const char *fmt, ...) { }
+#endif /* XDBC_TRACE */
+
+static int xdbc_bulk_transfer(void *data, int size, bool read);
+
+static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
+{
+	u32 val, sz;
+	u64 val64, sz64, mask64;
+	u8 byte;
+	void __iomem *base;
+
+	val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0);
+	write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, ~0);

drivers/usb/early/xhci-dbc.c line 60

Quoted 10 lines
drivers/usb/early/xhci-dbc.c new file +10 -0
+	sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0);
+	write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, val);
+	if (val == 0xffffffff || sz == 0xffffffff) {
+		pr_notice("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;

Is this cast necessary?

drivers/usb/early/xhci-dbc.c line 69

Quoted 9 lines
drivers/usb/early/xhci-dbc.c new file +9 -0
+
+	if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+		val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4);
+		write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, ~0);
+		sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4);
+		write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, val);
+
+		val64 |= (u64)val << 32;
+		sz64 |= (u64)sz << 32;

Could these type casts be avoided by declaring 'val' and 'sz' as u64 to begin with?

drivers/usb/early/xhci-dbc.c line 70

Quoted 1 line
drivers/usb/early/xhci-dbc.c new file +1 -0
+		mask64 |= (u64)~0 << 32;

Type cast could be avoided by using 0L.

Quoted 12 lines
drivers/usb/early/xhci-dbc.c new file +12 -0
+static u32 __init xdbc_find_dbgp(int xdbc_num, u32 *b, u32 *d, u32 *f)
+{
+	u32 bus, dev, func, class;
+
+	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)

drivers/usb/early/xhci-dbc.c line 131

Quoted 10 lines
drivers/usb/early/xhci-dbc.c new file +10 -0
+					continue;
+
+				*b = bus;
+				*d = dev;
+				*f = func;
+
+				return 0;
+			}
+		}
+	}

Nit: to me it would look more balanced visually if the body of the innermost loop started with an empty newline.

drivers/usb/early/xhci-dbc.c line 175

Quoted 2 lines
drivers/usb/early/xhci-dbc.c new file +2 -0
+	ext_cap_offset = xhci_find_next_ext_cap(xdbc.xhci_base,
+						0, XHCI_EXT_CAPS_LEGACY);

Please don't break this line. You can shorten the variable name if you want to save line length.

drivers/usb/early/xhci-dbc.c line 341

Quoted 7 lines
drivers/usb/early/xhci-dbc.c new file +7 -0
+	/* populate the contexts */
+	context = (struct xdbc_context *)xdbc.dbcc_base;
+	context->info.string0 = cpu_to_le64(xdbc.string_dma);
+	context->info.manufacturer = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH);
+	context->info.product = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 2);
+	context->info.serial = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 3);
+	context->info.length = cpu_to_le32(string_length);

Wouldn't this (and some of the other initializations) look nicer this way:

	/* Populate the contexts: */
	context = (struct xdbc_context *)xdbc.dbcc_base;

	context->info.string0		= cpu_to_le64(xdbc.string_dma);
	context->info.manufacturer	= cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH);
	context->info.product		= cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 2);
	context->info.serial		= cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 3);
	context->info.length		= cpu_to_le32(string_length);

?

drivers/usb/early/xhci-dbc.c line 901

Quoted 1 line
drivers/usb/early/xhci-dbc.c new file +1 -0
+	/* Check completion of the previous request. */

Could you please standardize the capitalization and punctuation of all the comments in the patches? Some are lower case, some are upper case, some have full stops, some don't.

One good style would be to use this form when a comment refers to what the next statement does:

	/* Check completion of the previous request: */
Quoted 21 lines
drivers/usb/early/xhci-dbc.c new file +21 -0
+/**
+ * struct xdbc_regs - xHCI Debug Capability Register interface.
+ */
+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;
+#define DEBUG_MAX_BURST(p)	(((p) >> 16) & 0xff)
+#define CTRL_DCR		BIT(0)		/* DbC Run */
+#define CTRL_PED		BIT(1)		/* Port Enable/Disable */
+#define CTRL_HOT		BIT(2)		/* Halt Out TR */
+#define CTRL_HIT		BIT(3)		/* Halt In TR */
+#define CTRL_DRC		BIT(4)		/* DbC run change */
+#define CTRL_DCE		BIT(31)		/* DbC enable */
+	__le32	status;
+#define DCST_DPN(p)		(((p) >> 24) & 0xff)
+	__le32	portsc;		/* Port status and control */

drivers/usb/early/xhci-dbc.c line 133

Quoted 10 lines
drivers/usb/early/xhci-dbc.c new file +10 -0
+#define PORTSC_CCS		BIT(0)
+#define PORTSC_CSC		BIT(17)
+#define PORTSC_PRC		BIT(21)
+#define PORTSC_PLC		BIT(22)
+#define PORTSC_CEC		BIT(23)
+	__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 */
+};

So why are defines intermixed with the fields? If the defines relate to the field then their naming sure does not express that ...

I was thinking of something like:

/**
* struct xdbc_regs - xHCI Debug Capability Register interface. */

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_DCR BIT(0) /* DbC Run */
#define CTRL_PED BIT(1) /* Port Enable/Disable */
#define CTRL_HOT BIT(2) /* Halt Out TR */
#define CTRL_HIT BIT(3) /* Halt In TR */
#define CTRL_DRC BIT(4) /* DbC run change */
#define CTRL_DCE BIT(31) /* DbC enable */

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

#define PORTSC_CCS BIT(0)
#define PORTSC_CSC BIT(17)
#define PORTSC_PRC BIT(21)
#define PORTSC_PLC BIT(22)
#define PORTSC_CEC BIT(23)

Also, the abbreviations suck big time. What's wrong with:

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

?

Also note how the comments became superfluous once descriptive names are chosen...

Please review the rest of the defines and series for similar problems and fix them, there are more of the same type.

Thanks,

Ingo

author
#3 lore raw

Re: [PATCH v6 1/4] usb: dbc: early driver for xhci debug capability

Hi Ingo,

Quoted 307 lines · Ingo Molnar
Quoted 6 lines · Lu Baolu

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.

Quoted 10 lines

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 xHCI host. There isn't any precondition from xHCI host side for DbC to work.

s/xHCI host/the xHCI host

Quoted 3 lines

This patch also includes bulk out and bulk in interfaces. These interfaces could be used to implement early printk bootconsole or hook to various system debuggers.

s/out/output
s/in/input

arch/x86/Kconfig.debug config EARLY_PRINTK_EFI · line 56

Quoted 2 lines
arch/x86/Kconfig.debug +2 -0
+config EARLY_PRINTK_USB_XDBC
+	bool "Early printk via xHCI debug port"

s/xHCI/the xHCI

I remarked on this in my first review as well - mind checking the whole series for uses of 'xHCI'?

Quoted 106 lines
arch/x86/Kconfig.debug +11 -0
+	depends on EARLY_PRINTK && PCI
+	select EARLY_PRINTK_USB
+	---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_CORE
 	def_bool n
drivers/usb/Kconfig +3 -0
index fbe493d..9313fff 100644
@@ -19,6 +19,9 @@ config USB_EHCI_BIG_ENDIAN_MMIO
 config USB_EHCI_BIG_ENDIAN_DESC
 	bool
 
+config USB_EARLY_PRINTK
+	bool
+
 menuconfig USB_SUPPORT
 	bool "USB support"
 	depends on HAS_IOMEM
drivers/usb/Makefile +1 -1
index 7791af6..53d1356 100644
@@ -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/
drivers/usb/early/Makefile +1 -0
index 24bbe51..fcde228 100644
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
+obj-$(CONFIG_EARLY_PRINTK_USB_XDBC) += xhci-dbc.o
drivers/usb/early/xhci-dbc.c new file +50 -0
new file mode 100644
index 0000000..72480c4
@@ -0,0 +1,1027 @@
+/**
+ * xhci-dbc.c - xHCI debug capability early driver
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Author: Lu Baolu <[email protected]>
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ":%s: " fmt, __func__
+
+#include <linux/console.h>
+#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/module.h>
+#include <linux/delay.h>
+
+#include "../host/xhci.h"
+#include "xhci-dbc.h"
+
+static struct xdbc_state xdbc;
+static int early_console_keep;
+
+#ifdef XDBC_TRACE
+#define	xdbc_trace	trace_printk
+#else
+static inline void xdbc_trace(const char *fmt, ...) { }
+#endif /* XDBC_TRACE */
+
+static int xdbc_bulk_transfer(void *data, int size, bool read);
+
+static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
+{
+	u32 val, sz;
+	u64 val64, sz64, mask64;
+	u8 byte;
+	void __iomem *base;
+
+	val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0);
+	write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, ~0);

drivers/usb/early/xhci-dbc.c line 60

Quoted 10 lines
drivers/usb/early/xhci-dbc.c new file +10 -0
+	sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0);
+	write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, val);
+	if (val == 0xffffffff || sz == 0xffffffff) {
+		pr_notice("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;

Is this cast necessary?

drivers/usb/early/xhci-dbc.c line 69

Quoted 9 lines
drivers/usb/early/xhci-dbc.c new file +9 -0
+
+	if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+		val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4);
+		write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, ~0);
+		sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4);
+		write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, val);
+
+		val64 |= (u64)val << 32;
+		sz64 |= (u64)sz << 32;

Could these type casts be avoided by declaring 'val' and 'sz' as u64 to begin with?

drivers/usb/early/xhci-dbc.c line 70

Quoted 1 line
drivers/usb/early/xhci-dbc.c new file +1 -0
+		mask64 |= (u64)~0 << 32;

Type cast could be avoided by using 0L.

Quoted 12 lines
drivers/usb/early/xhci-dbc.c new file +12 -0
+static u32 __init xdbc_find_dbgp(int xdbc_num, u32 *b, u32 *d, u32 *f)
+{
+	u32 bus, dev, func, class;
+
+	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)

drivers/usb/early/xhci-dbc.c line 131

Quoted 10 lines
drivers/usb/early/xhci-dbc.c new file +10 -0
+					continue;
+
+				*b = bus;
+				*d = dev;
+				*f = func;
+
+				return 0;
+			}
+		}
+	}

Nit: to me it would look more balanced visually if the body of the innermost loop started with an empty newline.

drivers/usb/early/xhci-dbc.c line 175

Quoted 2 lines
drivers/usb/early/xhci-dbc.c new file +2 -0
+	ext_cap_offset = xhci_find_next_ext_cap(xdbc.xhci_base,
+						0, XHCI_EXT_CAPS_LEGACY);

Please don't break this line. You can shorten the variable name if you want to save line length.

drivers/usb/early/xhci-dbc.c line 341

Quoted 7 lines
drivers/usb/early/xhci-dbc.c new file +7 -0
+	/* populate the contexts */
+	context = (struct xdbc_context *)xdbc.dbcc_base;
+	context->info.string0 = cpu_to_le64(xdbc.string_dma);
+	context->info.manufacturer = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH);
+	context->info.product = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 2);
+	context->info.serial = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 3);
+	context->info.length = cpu_to_le32(string_length);

Wouldn't this (and some of the other initializations) look nicer this way:

	/* Populate the contexts: */
	context = (struct xdbc_context *)xdbc.dbcc_base;

	context->info.string0		= cpu_to_le64(xdbc.string_dma);
	context->info.manufacturer	= cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH);
	context->info.product		= cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 2);
	context->info.serial		= cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 3);
	context->info.length		= cpu_to_le32(string_length);

?

drivers/usb/early/xhci-dbc.c line 901

Quoted 1 line
drivers/usb/early/xhci-dbc.c new file +1 -0
+	/* Check completion of the previous request. */

Could you please standardize the capitalization and punctuation of all the comments in the patches? Some are lower case, some are upper case, some have full stops, some don't.

One good style would be to use this form when a comment refers to what the next statement does:

	/* Check completion of the previous request: */
Quoted 21 lines
drivers/usb/early/xhci-dbc.c new file +21 -0
+/**
+ * struct xdbc_regs - xHCI Debug Capability Register interface.
+ */
+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;
+#define DEBUG_MAX_BURST(p)	(((p) >> 16) & 0xff)
+#define CTRL_DCR		BIT(0)		/* DbC Run */
+#define CTRL_PED		BIT(1)		/* Port Enable/Disable */
+#define CTRL_HOT		BIT(2)		/* Halt Out TR */
+#define CTRL_HIT		BIT(3)		/* Halt In TR */
+#define CTRL_DRC		BIT(4)		/* DbC run change */
+#define CTRL_DCE		BIT(31)		/* DbC enable */
+	__le32	status;
+#define DCST_DPN(p)		(((p) >> 24) & 0xff)
+	__le32	portsc;		/* Port status and control */

drivers/usb/early/xhci-dbc.c line 133

Quoted 10 lines
drivers/usb/early/xhci-dbc.c new file +10 -0
+#define PORTSC_CCS		BIT(0)
+#define PORTSC_CSC		BIT(17)
+#define PORTSC_PRC		BIT(21)
+#define PORTSC_PLC		BIT(22)
+#define PORTSC_CEC		BIT(23)
+	__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 */
+};

So why are defines intermixed with the fields? If the defines relate to the field then their naming sure does not express that ...

I was thinking of something like:

/**
* struct xdbc_regs - xHCI Debug Capability Register interface. */

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_DCR BIT(0) /* DbC Run */
#define CTRL_PED BIT(1) /* Port Enable/Disable */
#define CTRL_HOT BIT(2) /* Halt Out TR */
#define CTRL_HIT BIT(3) /* Halt In TR */
#define CTRL_DRC BIT(4) /* DbC run change */
#define CTRL_DCE BIT(31) /* DbC enable */

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

#define PORTSC_CCS BIT(0)
#define PORTSC_CSC BIT(17)
#define PORTSC_PRC BIT(21)
#define PORTSC_PLC BIT(22)
#define PORTSC_CEC BIT(23)

Also, the abbreviations suck big time. What's wrong with:

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

Quoted 6 lines

?

Also note how the comments became superfluous once descriptive names are chosen...

Please review the rest of the defines and series for similar problems and fix them, there are more of the same type.

Thank you for the comments.

I will correct all the code style issues you pointed out here. And, I will review all patches and fix the similar code styles.

Best regards,
Lu Baolu

author
#4 lore raw

PATCH v6 2/4 x86: add support for earlyprintk via USB3 debug port

In reply to Lu Baolu

Add support for early printk by writing debug messages to the
USB3 debug port. Users can use this type of early printk by
specifying kernel parameter of "earlyprintk=xdbc". This gives users a chance of providing debug output.

The hardware for USB3 debug port requires DMA memory blocks. This requires to delay setting up debugging hardware and registering boot console until the memblocks are filled.

---
 Documentation/admin-guide/kernel-parameters.txt | 1 +
 arch/x86/kernel/early_printk.c                  | 5 +++++
 arch/x86/kernel/setup.c                         | 4 ++++
 3 files changed, 10 insertions(+)
Documentation/admin-guide/kernel-parameters.txt +1 -0
index be7c0d9..4bf6138 100644
@@ -988,6 +988,7 @@
 			earlyprintk=ttySn[,baudrate]
 			earlyprintk=dbgp[debugController#]
 			earlyprintk=pciserial,bus:device.function[,baudrate]
+			earlyprintk=xdbc[xhciController#]
 
 			earlyprintk is useful when the kernel crashes before
 			the normal console is initialized. It is not enabled by
arch/x86/kernel/early_printk.c +5 -0
index 8a12199..0f08403 100644
@@ -17,6 +17,7 @@
 #include <asm/intel-mid.h>
 #include <asm/pgtable.h>
 #include <linux/usb/ehci_def.h>
+#include <linux/usb/xhci-dbgp.h>
 #include <linux/efi.h>
 #include <asm/efi.h>
 #include <asm/pci_x86.h>
@@ -381,6 +382,10 @@ static int __init setup_early_printk(char *buf)
 		if (!strncmp(buf, "efi", 3))
 			early_console_register(&early_efi_console, keep);
 #endif
+#ifdef CONFIG_EARLY_PRINTK_USB_XDBC
+		if (!strncmp(buf, "xdbc", 4))
+			early_xdbc_parse_parameter(buf + 4);
+#endif
 
 		buf++;
 	}
arch/x86/kernel/setup.c +4 -0
index 4cfba94..1f27d91 100644
@@ -70,6 +70,7 @@
 #include <linux/tboot.h>
 #include <linux/jiffies.h>
 
+#include <linux/usb/xhci-dbgp.h>
 #include <video/edid.h>
 
 #include <asm/mtrr.h>
@@ -1120,6 +1121,9 @@ void __init setup_arch(char **cmdline_p)
 	memblock_set_current_limit(ISA_END_ADDRESS);
 	memblock_x86_fill();
 
+	if (!early_xdbc_setup_hardware())
+		early_xdbc_register_console();
+
 	reserve_bios_regions();
 
 	if (efi_enabled(EFI_MEMMAP)) {
Signature · 1 line
2.1.4
author
#5 lore raw

PATCH v6 3/4 usb: serial: add dbc debug device support to usb_debug

In reply to Lu Baolu

This patch adds dbc debug device support to the usb_debug driver.

---
 drivers/usb/serial/usb_debug.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)
drivers/usb/serial/usb_debug.c +25 -3
index ca2fa5b..92f7e5c 100644
@@ -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,20 @@ 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,
+	.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");
Signature · 1 line
2.1.4
author
#6 lore raw

PATCH v6 4/4 usb: doc: add document for USB3 debug port usage

In reply to Lu Baolu

Add Documentation/usb/usb3-debug-port.rst. This document includes the user guide for USB3 debug port.

---
 Documentation/usb/usb3-debug-port.rst | 98 +++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 Documentation/usb/usb3-debug-port.rst
Documentation/usb/usb3-debug-port.rst new file +98 -0
new file mode 100644
index 0000000..9eddb3a
@@ -0,0 +1,98 @@
+===============
+USB3 debug port
+===============
+
+:Author: Lu Baolu <[email protected]>
+:Date: January 2017
+
+GENERAL
+=======
+
+This is a HOWTO for using USB3 debug port on x86 systems.
+
+Before using any kernel debugging functionality based on USB3
+debug port, you need to check 1) whether debug port is supported
+by the xHCI host; 2) which port is used for debugging purposes
+(normally the first USB3 root port). You must have a USB 3.0
+super-speed A-to-A debugging cable to connect the debug target
+with a debug host. In this document, "debug target" stands for
+the system under debugging, and "debug host" stands for a
+stand-alone system that is able to talk to the debugging target
+through the USB3 debug port.
+
+EARLY PRINTK
+============
+
+On the debug target system, you need to customize a debugging
+kernel with CONFIG_EARLY_PRINTK_USB_XDBC enabled. And, add
+below kernel boot parameter::
+
+	"earlyprintk=xdbc"
+
+If there are multiple xHCI controllers in the system, you can
+append a host contoller index to this kernel parameter. This
+index starts from 0.
+
+If you are going to use the "keep" option defined by the
+early printk framework to keep the boot console alive after
+early boot, you'd better add below kernel boot parameter::
+
+	"usbcore.autosuspend=-1"
+
+On the debug host side, you don't need to customize the kernel,
+but you'd better disable usb subsystem runtime power management
+by adding below kernel boot parameter::
+
+	"usbcore.autosuspend=-1"
+
+Before starting the debug target, you should connect the debug
+port on the debug target with a root port or port of any external
+hub on the debug host. The cable used to connect these two ports
+should be a USB 3.0 super-speed A-to-A debugging cable.
+
+During early boot of the debug target, DbC (xHCI debug engine for
+USB3 debug port) hardware will be detected and initialized. After
+initialization, the debug host should be able to enumerate the
+debug target as a debug device. The debug host will then bind the
+debug device with the usb_debug driver module and create the
+/dev/ttyUSB0 device.
+
+If the debug device enumeration goes smoothly, you should be able
+to see below kernel messages on the debug host::
+
+	# tail -f /var/log/kern.log
+	[ 1815.983374] usb 4-3: new SuperSpeed USB device number 4 using xhci_hcd
+	[ 1815.999595] usb 4-3: LPM exit latency is zeroed, disabling LPM.
+	[ 1815.999899] usb 4-3: New USB device found, idVendor=1d6b, idProduct=0004
+	[ 1815.999902] usb 4-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
+	[ 1815.999903] usb 4-3: Product: Remote GDB
+	[ 1815.999904] usb 4-3: Manufacturer: Linux
+	[ 1815.999905] usb 4-3: SerialNumber: 0001
+	[ 1816.000240] usb_debug 4-3:1.0: xhci_dbc converter detected
+	[ 1816.000360] usb 4-3: xhci_dbc converter now attached to ttyUSB0
+
+You can run below bash scripts on the debug host to read the kernel
+log sent from debug target.
+
+.. code-block:: sh
+
+	===== start of bash scripts =============
+	#!/bin/bash
+
+	while true ; do
+		while [ ! -d /sys/class/tty/ttyUSB0 ] ; do
+			:
+	done
+	cat /dev/ttyUSB0 >> xdbc.log
+	done
+	===== end of bash scripts ===============
+
+You should be able to see the early boot message in xdbc.log.
+
+If it doesn't work, please ask it on the <[email protected]>
+mailing list.
+
+Below USB hosts have been verified to work::
+
+	Intel Corporation Sunrise Point-H USB 3.0 xHCI Controller
+	Intel Corporation Wildcat Point-LP USB xHCI Controller
Signature · 1 line
2.1.4