s390: provide sclp based boot console
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Wed, 11 Jan 2017 08:14:52 +0000 (09:14 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 16 Jan 2017 06:27:55 +0000 (07:27 +0100)
Use the early sclp code to provide a boot console. This boot console
is available if the kernel parameter "earlyprintk" has been specified,
just like it works for other architectures that also provide an early
boot console.

This makes debugging of early problems much easier, since now we
finally have working console output even before memory detection is
running.

The boot console will be automatically disabled as soon as another
console will be registered.

Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Documentation/admin-guide/kernel-parameters.txt
arch/s390/Kconfig.debug
arch/s390/include/asm/sclp.h
arch/s390/kernel/Makefile
arch/s390/kernel/early_printk.c [new file with mode: 0644]
arch/s390/kernel/sclp.c

index be7c0d9506b12072219f0396ceb9072eeea03df8..ef77c55e87e2f560361e012c865d3a2361001f1e 100644 (file)
                        address. The serial port must already be setup
                        and configured. Options are not yet supported.
 
-       earlyprintk=    [X86,SH,BLACKFIN,ARM,M68k]
+       earlyprintk=    [X86,SH,BLACKFIN,ARM,M68k,S390]
                        earlyprintk=vga
                        earlyprintk=efi
+                       earlyprintk=sclp
                        earlyprintk=xen
                        earlyprintk=serial[,ttySn[,baudrate]]
                        earlyprintk=serial[,0x...[,baudrate]]
 
                        The xen output can only be used by Xen PV guests.
 
+                       The sclp output can only be used on s390.
+
        edac_report=    [HW,EDAC] Control how to report EDAC event
                        Format: {"on" | "off" | "force"}
                        on: enable EDAC to report H/W event. May be overridden
index 26c5d5beb4bebd2e060654d2d9d6e480f7f5da34..32b3e3bfd0227ad691b60da467a74b06cbd2e848 100644 (file)
@@ -20,4 +20,8 @@ config S390_PTDUMP
 config DEBUG_SET_MODULE_RONX
        def_bool y
        depends on MODULES
+
+config EARLY_PRINTK
+       def_bool y
+
 endmenu
index 8db92a5b3bf13ecf206b09bcc40fd4d3bd6a617c..415eaace3f1b244f3850d2740b9beb54672f7b0d 100644 (file)
@@ -118,6 +118,7 @@ int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count);
 int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count);
 void sclp_early_detect(void);
 void _sclp_print_early(const char *);
+void __sclp_print_early(const char *s, unsigned int len);
 void sclp_ocf_cpc_name_copy(char *dst);
 
 static inline int sclp_get_core_info(struct sclp_core_info *info, int early)
index 36b5101c8606e189e33c5dcc513f0c3fae326597..edbc62e040278207dd01ea94bf19a7a34084b082 100644 (file)
@@ -76,7 +76,7 @@ obj-$(CONFIG_AUDIT)           += audit.o
 compat-obj-$(CONFIG_AUDIT)     += compat_audit.o
 obj-$(CONFIG_COMPAT)           += compat_linux.o compat_signal.o
 obj-$(CONFIG_COMPAT)           += compat_wrapper.o $(compat-obj-y)
-
+obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
diff --git a/arch/s390/kernel/early_printk.c b/arch/s390/kernel/early_printk.c
new file mode 100644 (file)
index 0000000..54a4dc5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *    Copyright IBM Corp. 2017
+ */
+
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/sclp.h>
+
+static void sclp_early_write(struct console *con, const char *s, unsigned int len)
+{
+       __sclp_print_early(s, len);
+}
+
+static struct console sclp_early_console = {
+       .name  = "earlysclp",
+       .write = sclp_early_write,
+       .flags = CON_PRINTBUFFER | CON_BOOT,
+       .index = -1,
+};
+
+static int __init setup_early_printk(char *buf)
+{
+       if (early_console)
+               return 0;
+       /* Accept only "earlyprintk" and "earlyprintk=sclp" */
+       if (buf && strncmp(buf, "sclp", 4))
+               return 0;
+       if (!sclp.has_linemode && !sclp.has_vt220)
+               return 0;
+       early_console = &sclp_early_console;
+       register_console(early_console);
+       return 0;
+}
+early_param("earlyprintk", setup_early_printk);
index 53e391fe85770f56fdd13b7885dcaaa0fc3d2eba..f9c5b02d2685490a877c3ce0dfded544739159b7 100644 (file)
@@ -98,7 +98,7 @@ static int _sclp_setup(int disable)
 }
 
 /* Output multi-line text using SCLP Message interface. */
-static void _sclp_print_lm(const char *str)
+static void _sclp_print_lm(const char *str, unsigned int len)
 {
        static unsigned char write_head[] = {
                /* sccb header */
@@ -133,8 +133,9 @@ static void _sclp_print_lm(const char *str)
                0x00, 0x00, 0x00, 0x00                          /* 6 */
        };
        unsigned char *ptr, *end_ptr, ch;
-       unsigned int count;
+       unsigned int count, num;
 
+       num = 0;
        memcpy(_sclp_work_area, write_head, sizeof(write_head));
        ptr = _sclp_work_area + sizeof(write_head);
        end_ptr = _sclp_work_area + sizeof(_sclp_work_area) - 1;
@@ -142,7 +143,9 @@ static void _sclp_print_lm(const char *str)
                if (ptr + sizeof(write_mto) > end_ptr)
                        break;
                memcpy(ptr, write_mto, sizeof(write_mto));
-               for (count = sizeof(write_mto); (ch = *str++) != 0; count++) {
+               for (count = sizeof(write_mto); num < len; count++) {
+                       num++;
+                       ch = *str++;
                        if (ch == 0x0a)
                                break;
                        if (ptr > end_ptr)
@@ -155,7 +158,7 @@ static void _sclp_print_lm(const char *str)
                *(unsigned short *)(_sclp_work_area + 8) += count;
                *(unsigned short *)(_sclp_work_area + 0) += count;
                ptr += count;
-       } while (ch != 0);
+       } while (num < len);
 
        /* SCLP write data */
        _sclp_servc(0x00760005, _sclp_work_area);
@@ -164,7 +167,7 @@ static void _sclp_print_lm(const char *str)
 /* Output multi-line text (plus a newline) using SCLP VT220
  * interface.
  */
-static void _sclp_print_vt220(const char *str)
+static void _sclp_print_vt220(const char *str, unsigned int len)
 {
        static unsigned char const write_head[] = {
                /* sccb header */
@@ -174,7 +177,6 @@ static void _sclp_print_vt220(const char *str)
                0x00, 0x06,
                0x1a, 0x00, 0x00, 0x00,
        };
-       size_t len = strlen(str);
 
        if (sizeof(write_head) + len >= sizeof(_sclp_work_area))
                len = sizeof(_sclp_work_area) - sizeof(write_head) - 1;
@@ -194,13 +196,18 @@ static void _sclp_print_vt220(const char *str)
 /* Output one or more lines of text on the SCLP console (VT220 and /
  * or line-mode). All lines get terminated; no need for a trailing LF.
  */
-void _sclp_print_early(const char *str)
+void __sclp_print_early(const char *str, unsigned int len)
 {
        if (_sclp_setup(0) != 0)
                return;
        if (have_linemode)
-               _sclp_print_lm(str);
+               _sclp_print_lm(str, len);
        if (have_vt220)
-               _sclp_print_vt220(str);
+               _sclp_print_vt220(str, len);
        _sclp_setup(1);
 }
+
+void _sclp_print_early(const char *str)
+{
+       __sclp_print_early(str, strlen(str));
+}