1
linux/arch/s390/kernel/machine_kexec.c
Heiko Carstens 15e9b586e0 [S390] Reset infrastructure for re-IPL.
In case of re-IPL and diag308 doesn't work we have to reset all devices
manually and wait synchronously that each reset finished.
This patch adds the necessary infrastucture and the first exploiter of it.

Subsystems that need to add a function that needs to be called at re-IPL
may register/unregister this function via

struct reset_call {
	struct reset_call *next;
	void (*fn)(void);
};

void register_reset_call(struct reset_call *reset);
void unregister_reset_call(struct reset_call *reset);

When the registered function get called the context is:

- all cpus beside the current one are stopped
- all machine checks and interrupts are disabled
- prefixing is disabled
- a default machine check handler is available for use

The registered functions may not take any locks are sleep.

For the common I/O layer part of this patch:

Introduce a reset_call css_reset that does the following:
- clear all subchannels
- perform a rchp on all channel paths and wait for the resulting
  machine checks
This replaces the calls to clear_all_subchannels() and
cio_reset_channel_paths() for kexec and ccw reipl. reipl_ccw_dev() now
uses reipl_find_schid() to determine the subchannel id for a given
device id.
Also remove cio_reset_channel_paths() and friends since they are not
needed anymore.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
2006-12-04 15:40:26 +01:00

105 lines
2.2 KiB
C

/*
* arch/s390/kernel/machine_kexec.c
*
* (C) Copyright IBM Corp. 2005
*
* Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
*
*/
/*
* s390_machine_kexec.c - handle the transition of Linux booting another kernel
* on the S390 architecture.
*/
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <asm/cio.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/system.h>
#include <asm/smp.h>
#include <asm/reset.h>
static void kexec_halt_all_cpus(void *);
typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);
extern const unsigned char relocate_kernel[];
extern const unsigned long long relocate_kernel_len;
int
machine_kexec_prepare(struct kimage *image)
{
unsigned long reboot_code_buffer;
/* We don't support anything but the default image type for now. */
if (image->type != KEXEC_TYPE_DEFAULT)
return -EINVAL;
/* Get the destination where the assembler code should be copied to.*/
reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT;
/* Then copy it */
memcpy((void *) reboot_code_buffer, relocate_kernel,
relocate_kernel_len);
return 0;
}
void
machine_kexec_cleanup(struct kimage *image)
{
}
void
machine_shutdown(void)
{
printk(KERN_INFO "kexec: machine_shutdown called\n");
}
NORET_TYPE void
machine_kexec(struct kimage *image)
{
on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
for (;;);
}
extern void pfault_fini(void);
static void
kexec_halt_all_cpus(void *kernel_image)
{
static atomic_t cpuid = ATOMIC_INIT(-1);
int cpu;
struct kimage *image;
relocate_kernel_t data_mover;
#ifdef CONFIG_PFAULT
if (MACHINE_IS_VM)
pfault_fini();
#endif
if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1)
signal_processor(smp_processor_id(), sigp_stop);
/* Wait for all other cpus to enter stopped state */
for_each_online_cpu(cpu) {
if (cpu == smp_processor_id())
continue;
while (!smp_cpu_not_running(cpu))
cpu_relax();
}
s390_reset_system();
image = (struct kimage *) kernel_image;
data_mover = (relocate_kernel_t)
(page_to_pfn(image->control_code_page) << PAGE_SHIFT);
/* Call the moving routine */
(*data_mover) (&image->head, image->start);
}