Skip to content

Commit

Permalink
s390: provide sclp based boot console
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
heicarst authored and Martin Schwidefsky committed Jan 16, 2017
1 parent f031974 commit 89175cf
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 11 deletions.
5 changes: 4 additions & 1 deletion Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -979,9 +979,10 @@
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]]
Expand Down Expand Up @@ -1016,6 +1017,8 @@

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
Expand Down
4 changes: 4 additions & 0 deletions arch/s390/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions arch/s390/include/asm/sclp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 35 additions & 0 deletions arch/s390/kernel/early_printk.c
Original file line number Diff line number Diff line change
@@ -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);
25 changes: 16 additions & 9 deletions arch/s390/kernel/sclp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -133,16 +133,19 @@ 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;
do {
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)
Expand All @@ -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);
Expand All @@ -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 */
Expand All @@ -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;
Expand All @@ -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));
}

0 comments on commit 89175cf

Please sign in to comment.