Hi Ingo, I'm very appreciated for your review comments. I've put my replies in lines. On 01/19/2017 05:37 PM, Ingo Molnar wrote: > * Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> wrote: > >> 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. >> >> This code is designed to be only used for kernel debugging >> when machine crashes very early before the console code is >> initialized. For normal operation it is not recommended. >> >> Cc: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx> >> Signed-off-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> >> --- >> arch/x86/Kconfig.debug | 14 + >> drivers/usb/Kconfig | 3 + >> drivers/usb/Makefile | 2 +- >> drivers/usb/early/Makefile | 1 + >> drivers/usb/early/xhci-dbc.c | 1068 +++++++++++++++++++++++++++++++++++++++++ >> drivers/usb/early/xhci-dbc.h | 205 ++++++++ >> include/linux/usb/xhci-dbgp.h | 22 + >> 7 files changed, 1314 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 >> >> diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug >> index 67eec55..13e85b7 100644 >> --- a/arch/x86/Kconfig.debug >> +++ b/arch/x86/Kconfig.debug >> @@ -29,6 +29,7 @@ config EARLY_PRINTK >> config EARLY_PRINTK_DBGP >> bool "Early printk via EHCI debug port" >> depends on EARLY_PRINTK && PCI >> + select USB_EARLY_PRINTK >> ---help--- >> Write kernel log output directly into the EHCI debug port. >> >> @@ -48,6 +49,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_XDBC >> + bool "Early printk via xHCI debug port" >> + depends on EARLY_PRINTK && PCI >> + select USB_EARLY_PRINTK >> + ---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. > Could we please do this rename: > > s/EARLY_PRINTK_XDBC > EARLY_PRINTK_USB_XDBC > > ? > > As many people will not realize what 'xdbc' means, standalone - while "it's an > USB serial logging variant" is a lot more natural. > > >> +config USB_EARLY_PRINTK >> + bool > Also, could we standardize the nomencalture to not be a mixture of prefixes and > postfixes - i.e. standardize on postfixes (as commonly done in the Kconfig space) > and rename this one to EARLY_PRINTK_USB or so? > > You can see the prefix/postfix inconsistency here already: Sure. I will fix the names. Thanks. > >> -obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ >> +obj-$(CONFIG_USB_EARLY_PRINTK) += early/ >> +obj-$(CONFIG_EARLY_PRINTK_XDBC) += xhci-dbc.o >> +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); >> + 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; >> + } >> + if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == >> + PCI_BASE_ADDRESS_MEM_TYPE_64) { > Please don't break the line here. Sure. Will fix it. > >> + 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); >> + mask64 |= ((u64)~0 << 32); > Unnecessary parentheses. Sure. Will fix it. > >> + } >> + >> + sz64 &= mask64; >> + >> + if (sizeof(dma_addr_t) < 8 || !sz64) { >> + pr_notice("invalid mmio address\n"); >> + return NULL; >> + } > So this doesn't work on regular 32-bit kernels? I will run my code on a 32-bit kernel and remove this check if it passes the test. > >> +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); > Please no ugly linebreaks. Sorry. I will fix it. > >> +static void xdbc_runtime_delay(unsigned long count) >> +{ >> + udelay(count); >> +} >> +static void (*xdbc_delay)(unsigned long) = xdbc_early_delay; > Is this udelay() complication really necessary? udelay() should work fine even in > early code. It might not be precisely calibrated, but should be good enough. I tried udelay() in the early code. It's not precise enough for the hardware handshaking. > >> +static int handshake(void __iomem *ptr, u32 mask, u32 done, >> + int wait, int delay) > Please break lines more intelligently: > > static int > handshake(void __iomem *ptr, u32 mask, u32 done, int wait, int delay) Sure. I will fix it. > >> + ext_cap_offset = xhci_find_next_ext_cap(xdbc.xhci_base, >> + 0, XHCI_EXT_CAPS_LEGACY); > No ugly linebreaks please. There's a ton more in other parts of this patch and > other patches: please review all the other linebreaks (and ignore checkpatch.pl). > > For example this: > >> + xdbc.erst_base = xdbc.table_base + >> + index * XDBC_TABLE_ENTRY_SIZE; >> + xdbc.erst_dma = xdbc.table_dma + >> + index * XDBC_TABLE_ENTRY_SIZE; > should be: > > xdbc.erst_base = xdbc.table_base + index*XDBC_TABLE_ENTRY_SIZE; > xdbc.erst_dma = xdbc.table_dma + index*XDBC_TABLE_ENTRY_SIZE; > > which makes it much more readable, etc. Sure. These line breaks were added to make checkpatch.pl happy. I will review all the line breaks and make them more readable. > >> +static void early_xdbc_write(struct console *con, const char *str, u32 n) >> +{ >> + int chunk, ret; >> + static char buf[XDBC_MAX_PACKET]; >> + int use_cr = 0; >> + >> + if (!xdbc.xdbc_reg) >> + return; >> + memset(buf, 0, XDBC_MAX_PACKET); >> + while (n > 0) { >> + for (chunk = 0; chunk < XDBC_MAX_PACKET && n > 0; >> + str++, chunk++, n--) { >> + if (!use_cr && *str == '\n') { >> + use_cr = 1; >> + buf[chunk] = '\r'; >> + str--; >> + n++; >> + continue; >> + } >> + if (use_cr) >> + use_cr = 0; >> + buf[chunk] = *str; > Hm, why are newlines converted to \r\n unconditionally? Makes for a crappy minicom > log on the other side ... Yes. The usb ehci (usb2) debug port driver (drivers/usb/early/ehci-dbgp.c) does this. I kept the same for xhci (usb3). It turns out to be good for display on host side. > >> +static int __init xdbc_init(void) >> +{ >> + unsigned long flags; >> + void __iomem *base; >> + u32 offset; >> + int ret = 0; >> + >> + if (!(xdbc.flags & XDBC_FLAGS_INITIALIZED)) >> + return 0; >> + >> + xdbc_delay = xdbc_runtime_delay; >> + >> + /* >> + * It's time to shutdown DbC, so that the debug >> + * port could be reused by the host controller. > s/shutdown DbC > /shut down the DbC > > s/could be reused > /can be reused > > ? > Sure. I will fix it. Thanks. >> + */ >> + if (early_xdbc_console.index == -1 || >> + (early_xdbc_console.flags & CON_BOOT)) { >> + xdbc_trace("hardware not used any more\n"); > s/any more > anymore Sure. I will fix it. Thanks. > >> + raw_spin_lock_irqsave(&xdbc.lock, flags); >> + base = ioremap_nocache(xdbc.xhci_start, xdbc.xhci_length); > Ugh, ioremap() can sleep ... Oh, right. I will remove the remapping code and let it use the previously mapped one. > >> +/** >> + * 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 */ > Yeah, so thsbbrvtnssck. (these abbreviations suck) > > Why 'rvd0' - did we run out of letters? Please name it __reserved_0 and > __reserved_1 like we typically do in kernel code. Sure. I will fix it. Thanks. > >> + __le32 rsvd; >> + __le32 rsvdz[7]; >> + __le32 rsvd0[11]; > ditto. I will fix them. > >> +#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 { > Please put a newline between different types of definitions. Sure. > >> + char string0[XDBC_MAX_STRING_LENGTH]; >> + char manufacture[XDBC_MAX_STRING_LENGTH]; >> + char product[XDBC_MAX_STRING_LENGTH]; >> + char serial[XDBC_MAX_STRING_LENGTH]; > s/manufacture/manufacturer > > ? Sure. > >> +}; >> + >> +#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 */ >> + >> +/* >> + * 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; >> +}; >> + >> +#define XDBC_EPID_OUT 2 >> +#define XDBC_EPID_IN 3 >> + >> +struct xdbc_state { >> + /* pci device info*/ >> + u16 vendor; >> + u16 device; >> + u32 bus; >> + u32 dev; >> + u32 func; >> + void __iomem *xhci_base; >> + u64 xhci_start; >> + size_t xhci_length; >> + int port_number; >> +#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; >> + 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; > Please make the vertical tabulation of the fields consistent throughout the > structure. Look at it in a terminal and convince yourself that it's nice and > beautiful to look at! > > Also, if you mix CPP #defines into structure definitions then tabulate them in a > similar fashion. Sure. I will fix this. Thank you. Best regards, Lu Baolu -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html