Commit cf13f0ea authored by Heiko Carstens's avatar Heiko Carstens Committed by Linus Torvalds
Browse files

[PATCH] kexec: s390 support



Add kexec support for s390 architecture.

From: Milton Miller <miltonm@bga.com>

- Fix passing of first argument to relocate_kernel assembly.
- Fix Kconfig description.
- Remove wrong comment and comments that describe obvious things.
- Allow only KEXEC_TYPE_DEFAULT as image type -> dump not supported.

Acked-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent fce0d574
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -455,6 +455,14 @@ config NO_IDLE_HZ_INIT
	  The HZ timer is switched off in idle by default. That means the
	  HZ timer is already disabled at boot time.

config KEXEC
	bool "kexec system call (EXPERIMENTAL)"
	depends on EXPERIMENTAL
	help
	  kexec is a system call that implements the ability to shutdown your
	  current kernel, and to start another kernel.  It is like a reboot
	  but is independent of hardware/microcode support.

endmenu

config PCMCIA
+10 −0
Original line number Diff line number Diff line
@@ -25,6 +25,16 @@ obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.o

obj-$(CONFIG_VIRT_TIMER)	+= vtime.o

# Kexec part
S390_KEXEC_OBJS := machine_kexec.o crash.o
ifeq ($(CONFIG_ARCH_S390X),y)
S390_KEXEC_OBJS += relocate_kernel64.o
else
S390_KEXEC_OBJS += relocate_kernel.o
endif
obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)


#
# This is just to get the dependencies...
#
+8 −0
Original line number Diff line number Diff line
@@ -1441,3 +1441,11 @@ compat_sys_waitid_wrapper:
	lgfr	%r5,%r5			# int
	llgtr	%r6,%r6			# struct rusage_emu31 *
	jg	compat_sys_waitid

	.globl	compat_sys_kexec_load_wrapper
compat_sys_kexec_load_wrapper:
	llgfr	%r2,%r2			# unsigned long
	llgfr	%r3,%r3			# unsigned long
	llgtr	%r4,%r4			# struct kexec_segment *
	llgfr	%r5,%r5			# unsigned long
	jg	compat_sys_kexec_load
+17 −0
Original line number Diff line number Diff line
/*
 * arch/s390/kernel/crash.c
 *
 * (C) Copyright IBM Corp. 2005
 *
 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
 *
 */

#include <linux/threads.h>
#include <linux/kexec.h>

note_buf_t crash_notes[NR_CPUS];

void machine_crash_shutdown(void)
{
}
+98 −0
Original line number Diff line number Diff line
/*
 * 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 <asm/cio.h>
#include <asm/setup.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/system.h>

static void kexec_halt_all_cpus(void *);

typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);

const extern unsigned char relocate_kernel[];
const extern 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)
{
	clear_all_subchannels();

	/* Disable lowcore protection */
	ctl_clear_bit(0,28);

	on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
	for(;;);
}

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;

	if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid))
		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();
	}

	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);
}
Loading