Commit 2332ce1a authored by Holger Smolinski's avatar Holger Smolinski Committed by Martin Schwidefsky

[S390] console flush on panic / reboot

The s390 console drivers use the unblank callback of the console
structure to flush the console buffer. In case of a panic or a
reboot the CPU doing the callback can block on the console i/o.
The other CPUs in the system continue to work. For panic this is
not a good idea.

Replace the unblank callback with proper panic/reboot notifier.
These get called after all but one CPU have been stopped.
Signed-off-by: default avatarHolger Smolinski <Holger.Smolinski@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 15e86b0c
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/reboot.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
...@@ -775,11 +776,11 @@ static struct tty_driver *con3215_device(struct console *c, int *index) ...@@ -775,11 +776,11 @@ static struct tty_driver *con3215_device(struct console *c, int *index)
} }
/* /*
* panic() calls console_unblank before the system enters a * panic() calls con3215_flush through a panic_notifier
* disabled, endless loop. * before the system enters a disabled, endless loop.
*/ */
static void static void
con3215_unblank(void) con3215_flush(void)
{ {
struct raw3215_info *raw; struct raw3215_info *raw;
unsigned long flags; unsigned long flags;
...@@ -790,6 +791,23 @@ con3215_unblank(void) ...@@ -790,6 +791,23 @@ con3215_unblank(void)
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
} }
static int con3215_notify(struct notifier_block *self,
unsigned long event, void *data)
{
con3215_flush();
return NOTIFY_OK;
}
static struct notifier_block on_panic_nb = {
.notifier_call = con3215_notify,
.priority = 0,
};
static struct notifier_block on_reboot_nb = {
.notifier_call = con3215_notify,
.priority = 0,
};
/* /*
* The console structure for the 3215 console * The console structure for the 3215 console
*/ */
...@@ -797,7 +815,6 @@ static struct console con3215 = { ...@@ -797,7 +815,6 @@ static struct console con3215 = {
.name = "ttyS", .name = "ttyS",
.write = con3215_write, .write = con3215_write,
.device = con3215_device, .device = con3215_device,
.unblank = con3215_unblank,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
}; };
...@@ -859,6 +876,8 @@ con3215_init(void) ...@@ -859,6 +876,8 @@ con3215_init(void)
raw3215[0] = NULL; raw3215[0] = NULL;
return -ENODEV; return -ENODEV;
} }
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
register_reboot_notifier(&on_reboot_nb);
register_console(&con3215); register_console(&con3215);
return 0; return 0;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/reboot.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/cio.h> #include <asm/cio.h>
...@@ -528,11 +529,11 @@ con3270_wait_write(struct con3270 *cp) ...@@ -528,11 +529,11 @@ con3270_wait_write(struct con3270 *cp)
} }
/* /*
* panic() calls console_unblank before the system enters a * panic() calls con3270_flush through a panic_notifier
* disabled, endless loop. * before the system enters a disabled, endless loop.
*/ */
static void static void
con3270_unblank(void) con3270_flush(void)
{ {
struct con3270 *cp; struct con3270 *cp;
unsigned long flags; unsigned long flags;
...@@ -554,6 +555,23 @@ con3270_unblank(void) ...@@ -554,6 +555,23 @@ con3270_unblank(void)
spin_unlock_irqrestore(&cp->view.lock, flags); spin_unlock_irqrestore(&cp->view.lock, flags);
} }
static int con3270_notify(struct notifier_block *self,
unsigned long event, void *data)
{
con3270_flush();
return NOTIFY_OK;
}
static struct notifier_block on_panic_nb = {
.notifier_call = con3270_notify,
.priority = 0,
};
static struct notifier_block on_reboot_nb = {
.notifier_call = con3270_notify,
.priority = 0,
};
/* /*
* The console structure for the 3270 console * The console structure for the 3270 console
*/ */
...@@ -561,7 +579,6 @@ static struct console con3270 = { ...@@ -561,7 +579,6 @@ static struct console con3270 = {
.name = "tty3270", .name = "tty3270",
.write = con3270_write, .write = con3270_write,
.device = con3270_device, .device = con3270_device,
.unblank = con3270_unblank,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
}; };
...@@ -623,6 +640,8 @@ con3270_init(void) ...@@ -623,6 +640,8 @@ con3270_init(void)
condev->cline->len = 0; condev->cline->len = 0;
con3270_create_status(condev); con3270_create_status(condev);
condev->input = alloc_string(&condev->freemem, 80); condev->input = alloc_string(&condev->freemem, 80);
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
register_reboot_notifier(&on_reboot_nb);
register_console(&con3270); register_console(&con3270);
return 0; return 0;
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/termios.h> #include <linux/termios.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/reboot.h>
#include "sclp.h" #include "sclp.h"
#include "sclp_rw.h" #include "sclp_rw.h"
...@@ -172,7 +173,7 @@ sclp_console_device(struct console *c, int *index) ...@@ -172,7 +173,7 @@ sclp_console_device(struct console *c, int *index)
* will be flushed to the SCLP. * will be flushed to the SCLP.
*/ */
static void static void
sclp_console_unblank(void) sclp_console_flush(void)
{ {
unsigned long flags; unsigned long flags;
...@@ -188,6 +189,24 @@ sclp_console_unblank(void) ...@@ -188,6 +189,24 @@ sclp_console_unblank(void)
spin_unlock_irqrestore(&sclp_con_lock, flags); spin_unlock_irqrestore(&sclp_con_lock, flags);
} }
static int
sclp_console_notify(struct notifier_block *self,
unsigned long event, void *data)
{
sclp_console_flush();
return NOTIFY_OK;
}
static struct notifier_block on_panic_nb = {
.notifier_call = sclp_console_notify,
.priority = 1,
};
static struct notifier_block on_reboot_nb = {
.notifier_call = sclp_console_notify,
.priority = 1,
};
/* /*
* used to register the SCLP console to the kernel and to * used to register the SCLP console to the kernel and to
* give printk necessary information * give printk necessary information
...@@ -197,7 +216,6 @@ static struct console sclp_console = ...@@ -197,7 +216,6 @@ static struct console sclp_console =
.name = sclp_console_name, .name = sclp_console_name,
.write = sclp_console_write, .write = sclp_console_write,
.device = sclp_console_device, .device = sclp_console_device,
.unblank = sclp_console_unblank,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
.index = 0 /* ttyS0 */ .index = 0 /* ttyS0 */
}; };
...@@ -241,6 +259,8 @@ sclp_console_init(void) ...@@ -241,6 +259,8 @@ sclp_console_init(void)
sclp_con_width_htab = 8; sclp_con_width_htab = 8;
/* enable printk-access to this driver */ /* enable printk-access to this driver */
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
register_reboot_notifier(&on_reboot_nb);
register_console(&sclp_console); register_console(&sclp_console);
return 0; return 0;
} }
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/reboot.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "sclp.h" #include "sclp.h"
...@@ -743,24 +745,30 @@ sclp_vt220_con_device(struct console *c, int *index) ...@@ -743,24 +745,30 @@ sclp_vt220_con_device(struct console *c, int *index)
return sclp_vt220_driver; return sclp_vt220_driver;
} }
/* static int
* This routine is called from panic when the kernel is going to give up. sclp_vt220_notify(struct notifier_block *self,
* We have to make sure that all buffers will be flushed to the SCLP. unsigned long event, void *data)
* Note that this function may be called from within an interrupt context.
*/
static void
sclp_vt220_con_unblank(void)
{ {
__sclp_vt220_flush_buffer(); __sclp_vt220_flush_buffer();
return NOTIFY_OK;
} }
static struct notifier_block on_panic_nb = {
.notifier_call = sclp_vt220_notify,
.priority = 1,
};
static struct notifier_block on_reboot_nb = {
.notifier_call = sclp_vt220_notify,
.priority = 1,
};
/* Structure needed to register with printk */ /* Structure needed to register with printk */
static struct console sclp_vt220_console = static struct console sclp_vt220_console =
{ {
.name = SCLP_VT220_CONSOLE_NAME, .name = SCLP_VT220_CONSOLE_NAME,
.write = sclp_vt220_con_write, .write = sclp_vt220_con_write,
.device = sclp_vt220_con_device, .device = sclp_vt220_con_device,
.unblank = sclp_vt220_con_unblank,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
.index = SCLP_VT220_CONSOLE_INDEX .index = SCLP_VT220_CONSOLE_INDEX
}; };
...@@ -776,6 +784,8 @@ sclp_vt220_con_init(void) ...@@ -776,6 +784,8 @@ sclp_vt220_con_init(void)
if (rc) if (rc)
return rc; return rc;
/* Attach linux console */ /* Attach linux console */
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
register_reboot_notifier(&on_reboot_nb);
register_console(&sclp_vt220_console); register_console(&sclp_vt220_console);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment