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. Signed-off-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> --- Documentation/kernel-parameters.txt | 1 + arch/x86/Kconfig.debug | 2 ++ arch/x86/kernel/early_printk.c | 5 +++++ drivers/usb/Kconfig | 3 +++ drivers/usb/Makefile | 2 +- drivers/usb/early/xhci-dbc.c | 43 +++++++++++++++++++++++++++++++++++++ include/linux/usb/xhci-dbc.h | 5 +++++ 7 files changed, 60 insertions(+), 1 deletion(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 87d40a7..460dc73 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1067,6 +1067,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. 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 diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index ba60cb1..d470071 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. @@ -51,6 +52,7 @@ config EARLY_PRINTK_EFI 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. diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index 21bf924..ba4c471 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -17,6 +17,7 @@ #include <asm/intel-mid.h> #include <asm/pgtable.h> #include <linux/usb/ehci_def.h> +#include <linux/usb/xhci-dbc.h> #include <linux/efi.h> #include <asm/efi.h> #include <asm/pci_x86.h> @@ -373,6 +374,10 @@ static int __init setup_early_printk(char *buf) if (!strncmp(buf, "dbgp", 4) && !early_dbgp_init(buf + 4)) early_console_register(&early_dbgp_console, keep); #endif +#ifdef CONFIG_EARLY_PRINTK_XDBC + if (!strncmp(buf, "xdbc", 4) && !early_xdbc_init(buf + 4)) + early_console_register(&early_xdbc_console, keep); +#endif #ifdef CONFIG_HVC_XEN if (!strncmp(buf, "xen", 3)) early_console_register(&xenboot_console, keep); diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 8ed451d..1c4dc23 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -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 diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index d5c57f1..6ff98ae 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -48,7 +48,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB) += misc/ -obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ +obj-$(CONFIG_USB_EARLY_PRINTK) += early/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 344d93e..6c24ba0 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -10,6 +10,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/console.h> #include <linux/pci_regs.h> #include <linux/pci_ids.h> #include <linux/bootmem.h> @@ -1319,3 +1320,45 @@ int xdbc_bulk_write(const char *bytes, int size) return ret; } + +/* + * Start a bulk-in or bulk-out transfer, wait until transfer completion + * or error. Return the count of actually transferred bytes or error. + */ +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 (!xdbcp->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; + } + if (chunk > 0) { + ret = xdbc_bulk_write(buf, chunk); + if (ret < 0) + break; + } + } +} + +struct console early_xdbc_console = { + .name = "earlyxdbc", + .write = early_xdbc_write, + .flags = CON_PRINTBUFFER, + .index = -1, +}; diff --git a/include/linux/usb/xhci-dbc.h b/include/linux/usb/xhci-dbc.h index 289ba58..a556eb8 100644 --- a/include/linux/usb/xhci-dbc.h +++ b/include/linux/usb/xhci-dbc.h @@ -216,4 +216,9 @@ struct xdbc_state { #define xdbc_read64(regs) xhci_read_64(NULL, (regs)) #define xdbc_write64(val, regs) xhci_write_64(NULL, (val), (regs)) +#ifdef CONFIG_EARLY_PRINTK_XDBC +extern int early_xdbc_init(char *s); +extern struct console early_xdbc_console; +#endif /* CONFIG_EARLY_PRINTK_XDBC */ + #endif /* __LINUX_XHCI_DBC_H */ -- 2.1.4 -- 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