Subject: Re: [PATCH] powerpc/powernv: Remove OPAL v1 takeover

From: Mike Qiu <[email-masked]>
Date: Tue, 24 Jun 2014 15:50:47 +0800

Reported-and-tested-by: Mike Qiu <[email-masked]>

Thanks
Mike
On 06/24/2014 03:17 PM, Michael Ellerman wrote:
> In commit 27f4488872d9 "Add OPAL takeover from PowerVM" we added support
> for "takeover" on OPAL v1 machines.
>
> This was a mode of operation where we would boot under pHyp, and query
> for the presence of OPAL. If detected we would then do a special
> sequence to take over the machine, and the kernel would end up running
> in hypervisor mode.
>
> OPAL v1 was never a supported product, and was never shipped outside
> IBM. As far as we know no one is still using it.
>
> Newer versions of OPAL do not use the takeover mechanism. Although the
> query for OPAL should be harmless on machines with newer OPAL, we have
> seen a machine where it causes a crash in Open Firmware.
>
> The code in early_init_devtree() to copy boot_command_line into cmd_line
> was added in commit 817c21ad9a1f "Get kernel command line accross OPAL
> takeover", and AFAIK is only used by takeover, so should also be
> removed.
>
> Signed-off-by: Michael Ellerman <[email-masked]>
> ---
>   arch/powerpc/Kconfig.debug                     |   1 -
>   arch/powerpc/include/asm/opal.h                |  29 ----
>   arch/powerpc/kernel/prom.c                     |   7 -
>   arch/powerpc/kernel/prom_init.c                | 211 -------------------------
>   arch/powerpc/kernel/prom_init_check.sh         |   4 +-
>   arch/powerpc/platforms/powernv/Makefile        |   2 +-
>   arch/powerpc/platforms/powernv/opal-takeover.S | 140 ----------------
>   7 files changed, 2 insertions(+), 392 deletions(-)
>   delete mode 100644 arch/powerpc/platforms/powernv/opal-takeover.S
>
> diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
> index 790352f..35d16bd 100644
> --- a/arch/powerpc/Kconfig.debug
> +++ b/arch/powerpc/Kconfig.debug
> @@ -303,7 +303,6 @@ config PPC_EARLY_DEBUG_OPAL_VTERMNO
>   	  This correspond to which /dev/hvcN you want to use for early
>   	  debug.
>   
> -	  On OPAL v1 (takeover) this should always be 0
>   	  On OPAL v2, this will be 0 for network console and 1 or 2 for
>   	  the machine built-in serial ports.
>   
> diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
> index 4600188..0da1dbd 100644
> --- a/arch/powerpc/include/asm/opal.h
> +++ b/arch/powerpc/include/asm/opal.h
> @@ -12,27 +12,7 @@
>   #ifndef __OPAL_H
>   #define __OPAL_H
>   
> -/****** Takeover interface ********/
> -
> -/* PAPR H-Call used to querty the HAL existence and/or instanciate
> - * it from within pHyp (tech preview only).
> - *
> - * This is exclusively used in prom_init.c
> - */
> -
>   #ifndef __ASSEMBLY__
> -
> -struct opal_takeover_args {
> -	u64	k_image;		/* r4 */
> -	u64	k_size;			/* r5 */
> -	u64	k_entry;		/* r6 */
> -	u64	k_entry2;		/* r7 */
> -	u64	hal_addr;		/* r8 */
> -	u64	rd_image;		/* r9 */
> -	u64	rd_size;		/* r10 */
> -	u64	rd_loc;			/* r11 */
> -};
> -
>   /*
>    * SG entry
>    *
> @@ -55,15 +35,6 @@ struct opal_sg_list {
>   /* We calculate number of sg entries based on PAGE_SIZE */
>   #define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry))
>   
> -extern long opal_query_takeover(u64 *hal_size, u64 *hal_align);
> -
> -extern long opal_do_takeover(struct opal_takeover_args *args);
> -
> -struct rtas_args;
> -extern int opal_enter_rtas(struct rtas_args *args,
> -			   unsigned long data,
> -			   unsigned long entry);
> -
>   #endif /* __ASSEMBLY__ */
>   
>   /****** OPAL APIs ******/
> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
> index 613a860..b694b07 100644
> --- a/arch/powerpc/kernel/prom.c
> +++ b/arch/powerpc/kernel/prom.c
> @@ -662,13 +662,6 @@ void __init early_init_devtree(void *params)
>   	of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL);
>   #endif
>   
> -	/* Pre-initialize the cmd_line with the content of boot_commmand_line,
> -	 * which will be empty except when the content of the variable has
> -	 * been overriden by a bootloading mechanism. This happens typically
> -	 * with HAL takeover
> -	 */
> -	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
> -
>   	/* Retrieve various informations from the /chosen node of the
>   	 * device-tree, including the platform type, initrd location and
>   	 * size, TCE reserve, and more ...
> diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
> index 078145a..1a85d8f 100644
> --- a/arch/powerpc/kernel/prom_init.c
> +++ b/arch/powerpc/kernel/prom_init.c
> @@ -1268,201 +1268,6 @@ static u64 __initdata prom_opal_base;
>   static u64 __initdata prom_opal_entry;
>   #endif
>   
> -#ifdef __BIG_ENDIAN__
> -/* XXX Don't change this structure without updating opal-takeover.S */
> -static struct opal_secondary_data {
> -	s64				ack;	/*  0 */
> -	u64				go;	/*  8 */
> -	struct opal_takeover_args	args;	/* 16 */
> -} opal_secondary_data;
> -
> -static u64 __initdata prom_opal_align;
> -static u64 __initdata prom_opal_size;
> -static int __initdata prom_rtas_start_cpu;
> -static u64 __initdata prom_rtas_data;
> -static u64 __initdata prom_rtas_entry;
> -
> -extern char opal_secondary_entry;
> -
> -static void __init prom_query_opal(void)
> -{
> -	long rc;
> -
> -	/* We must not query for OPAL presence on a machine that
> -	 * supports TNK takeover (970 blades), as this uses the same
> -	 * h-call with different arguments and will crash
> -	 */
> -	if (PHANDLE_VALID(call_prom("finddevice", 1, 1,
> -				    ADDR("/tnk-memory-map")))) {
> -		prom_printf("TNK takeover detected, skipping OPAL check\n");
> -		return;
> -	}
> -
> -	prom_printf("Querying for OPAL presence... ");
> -
> -	rc = opal_query_takeover(&prom_opal_size,
> -				 &prom_opal_align);
> -	prom_debug("(rc = %ld) ", rc);
> -	if (rc != 0) {
> -		prom_printf("not there.\n");
> -		return;
> -	}
> -	of_platform = PLATFORM_OPAL;
> -	prom_printf(" there !\n");
> -	prom_debug("  opal_size  = 0x%lx\n", prom_opal_size);
> -	prom_debug("  opal_align = 0x%lx\n", prom_opal_align);
> -	if (prom_opal_align < 0x10000)
> -		prom_opal_align = 0x10000;
> -}
> -
> -static int __init prom_rtas_call(int token, int nargs, int nret,
> -				 int *outputs, ...)
> -{
> -	struct rtas_args rtas_args;
> -	va_list list;
> -	int i;
> -
> -	rtas_args.token = token;
> -	rtas_args.nargs = nargs;
> -	rtas_args.nret  = nret;
> -	rtas_args.rets  = (rtas_arg_t *)&(rtas_args.args[nargs]);
> -	va_start(list, outputs);
> -	for (i = 0; i < nargs; ++i)
> -		rtas_args.args[i] = va_arg(list, rtas_arg_t);
> -	va_end(list);
> -
> -	for (i = 0; i < nret; ++i)
> -		rtas_args.rets[i] = 0;
> -
> -	opal_enter_rtas(&rtas_args, prom_rtas_data,
> -			prom_rtas_entry);
> -
> -	if (nret > 1 && outputs != NULL)
> -		for (i = 0; i < nret-1; ++i)
> -			outputs[i] = rtas_args.rets[i+1];
> -	return (nret > 0)? rtas_args.rets[0]: 0;
> -}
> -
> -static void __init prom_opal_hold_cpus(void)
> -{
> -	int i, cnt, cpu, rc;
> -	long j;
> -	phandle node;
> -	char type[64];
> -	u32 servers[8];
> -	void *entry = (unsigned long *)&opal_secondary_entry;
> -	struct opal_secondary_data *data = &opal_secondary_data;
> -
> -	prom_debug("prom_opal_hold_cpus: start...\n");
> -	prom_debug("    - entry       = 0x%x\n", entry);
> -	prom_debug("    - data        = 0x%x\n", data);
> -
> -	data->ack = -1;
> -	data->go = 0;
> -
> -	/* look for cpus */
> -	for (node = 0; prom_next_node(&node); ) {
> -		type[0] = 0;
> -		prom_getprop(node, "device_type", type, sizeof(type));
> -		if (strcmp(type, "cpu") != 0)
> -			continue;
> -
> -		/* Skip non-configured cpus. */
> -		if (prom_getprop(node, "status", type, sizeof(type)) > 0)
> -			if (strcmp(type, "okay") != 0)
> -				continue;
> -
> -		cnt = prom_getprop(node, "ibm,ppc-interrupt-server#s", servers,
> -			     sizeof(servers));
> -		if (cnt == PROM_ERROR)
> -			break;
> -		cnt >>= 2;
> -		for (i = 0; i < cnt; i++) {
> -			cpu = servers[i];
> -			prom_debug("CPU %d ... ", cpu);
> -			if (cpu == prom.cpu) {
> -				prom_debug("booted !\n");
> -				continue;
> -			}
> -			prom_debug("starting ... ");
> -
> -			/* Init the acknowledge var which will be reset by
> -			 * the secondary cpu when it awakens from its OF
> -			 * spinloop.
> -			 */
> -			data->ack = -1;
> -			rc = prom_rtas_call(prom_rtas_start_cpu, 3, 1,
> -					    NULL, cpu, entry, data);
> -			prom_debug("rtas rc=%d ...", rc);
> -
> -			for (j = 0; j < 100000000 && data->ack == -1; j++) {
> -				HMT_low();
> -				mb();
> -			}
> -			HMT_medium();
> -			if (data->ack != -1)
> -				prom_debug("done, PIR=0x%x\n", data->ack);
> -			else
> -				prom_debug("timeout !\n");
> -		}
> -	}
> -	prom_debug("prom_opal_hold_cpus: end...\n");
> -}
> -
> -static void __init prom_opal_takeover(void)
> -{
> -	struct opal_secondary_data *data = &opal_secondary_data;
> -	struct opal_takeover_args *args = &data->args;
> -	u64 align = prom_opal_align;
> -	u64 top_addr, opal_addr;
> -
> -	args->k_image	= (u64)_stext;
> -	args->k_size	= _end - _stext;
> -	args->k_entry	= 0;
> -	args->k_entry2	= 0x60;
> -
> -	top_addr = _ALIGN_UP(args->k_size, align);
> -
> -	if (prom_initrd_start != 0) {
> -		args->rd_image = prom_initrd_start;
> -		args->rd_size = prom_initrd_end - args->rd_image;
> -		args->rd_loc = top_addr;
> -		top_addr = _ALIGN_UP(args->rd_loc + args->rd_size, align);
> -	}
> -
> -	/* Pickup an address for the HAL. We want to go really high
> -	 * up to avoid problem with future kexecs. On the other hand
> -	 * we don't want to be all over the TCEs on P5IOC2 machines
> -	 * which are going to be up there too. We assume the machine
> -	 * has plenty of memory, and we ask for the HAL for now to
> -	 * be just below the 1G point, or above the initrd
> -	 */
> -	opal_addr = _ALIGN_DOWN(0x40000000 - prom_opal_size, align);
> -	if (opal_addr < top_addr)
> -		opal_addr = top_addr;
> -	args->hal_addr = opal_addr;
> -
> -	/* Copy the command line to the kernel image */
> -	strlcpy(boot_command_line, prom_cmd_line,
> -		COMMAND_LINE_SIZE);
> -
> -	prom_debug("  k_image    = 0x%lx\n", args->k_image);
> -	prom_debug("  k_size     = 0x%lx\n", args->k_size);
> -	prom_debug("  k_entry    = 0x%lx\n", args->k_entry);
> -	prom_debug("  k_entry2   = 0x%lx\n", args->k_entry2);
> -	prom_debug("  hal_addr   = 0x%lx\n", args->hal_addr);
> -	prom_debug("  rd_image   = 0x%lx\n", args->rd_image);
> -	prom_debug("  rd_size    = 0x%lx\n", args->rd_size);
> -	prom_debug("  rd_loc     = 0x%lx\n", args->rd_loc);
> -	prom_printf("Performing OPAL takeover,this can take a few minutes..\n");
> -	prom_close_stdin();
> -	mb();
> -	data->go = 1;
> -	for (;;)
> -		opal_do_takeover(args);
> -}
> -#endif /* __BIG_ENDIAN__ */
> -
>   /*
>    * Allocate room for and instantiate OPAL
>    */
> @@ -1597,12 +1402,6 @@ static void __init prom_instantiate_rtas(void)
>   			 &val, sizeof(val)) != PROM_ERROR)
>   		rtas_has_query_cpu_stopped = true;
>   
> -#if defined(CONFIG_PPC_POWERNV) && defined(__BIG_ENDIAN__)
> -	/* PowerVN takeover hack */
> -	prom_rtas_data = base;
> -	prom_rtas_entry = entry;
> -	prom_getprop(rtas_node, "start-cpu", &prom_rtas_start_cpu, 4);
> -#endif
>   	prom_debug("rtas base     = 0x%x\n", base);
>   	prom_debug("rtas entry    = 0x%x\n", entry);
>   	prom_debug("rtas size     = 0x%x\n", (long)size);
> @@ -3027,16 +2826,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
>   		prom_instantiate_rtas();
>   
>   #ifdef CONFIG_PPC_POWERNV
> -#ifdef __BIG_ENDIAN__
> -	/* Detect HAL and try instanciating it & doing takeover */
> -	if (of_platform == PLATFORM_PSERIES_LPAR) {
> -		prom_query_opal();
> -		if (of_platform == PLATFORM_OPAL) {
> -			prom_opal_hold_cpus();
> -			prom_opal_takeover();
> -		}
> -	} else
> -#endif /* __BIG_ENDIAN__ */
>   	if (of_platform == PLATFORM_OPAL)
>   		prom_instantiate_opal();
>   #endif /* CONFIG_PPC_POWERNV */
> diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh
> index 77aa1e9..fe8e54b 100644
> --- a/arch/powerpc/kernel/prom_init_check.sh
> +++ b/arch/powerpc/kernel/prom_init_check.sh
> @@ -21,9 +21,7 @@ _end enter_prom memcpy memset reloc_offset __secondary_hold
>   __secondary_hold_acknowledge __secondary_hold_spinloop __start
>   strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224
>   reloc_got2 kernstart_addr memstart_addr linux_banner _stext
> -opal_query_takeover opal_do_takeover opal_enter_rtas opal_secondary_entry
> -boot_command_line __prom_init_toc_start __prom_init_toc_end
> -btext_setup_display TOC."
> +__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC."
>   
>   NM="$1"
>   OBJ="$2"
> diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
> index d55891f..4ad227d 100644
> --- a/arch/powerpc/platforms/powernv/Makefile
> +++ b/arch/powerpc/platforms/powernv/Makefile
> @@ -1,4 +1,4 @@
> -obj-y			+= setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
> +obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o
>   obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
>   obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
>   obj-y			+= opal-msglog.o
> diff --git a/arch/powerpc/platforms/powernv/opal-takeover.S b/arch/powerpc/platforms/powernv/opal-takeover.S
> deleted file mode 100644
> index 11a3169..0000000
> --- a/arch/powerpc/platforms/powernv/opal-takeover.S
> +++ /dev/null
> @@ -1,140 +0,0 @@
> -/*
> - * PowerNV OPAL takeover assembly code, for use by prom_init.c
> - *
> - * Copyright 2011 IBM Corp.
> - *
> - * This program is free software; you can redistribute it and/or
> - * modify it under the terms of the GNU General Public License
> - * as published by the Free Software Foundation; either version
> - * 2 of the License, or (at your option) any later version.
> - */
> -
> -#include <asm/ppc_asm.h>
> -#include <asm/hvcall.h>
> -#include <asm/asm-offsets.h>
> -#include <asm/opal.h>
> -
> -#define H_HAL_TAKEOVER			0x5124
> -#define H_HAL_TAKEOVER_QUERY_MAGIC	-1
> -
> -	.text
> -_GLOBAL(opal_query_takeover)
> -	mfcr	r0
> -	stw	r0,8(r1)
> -	stdu	r1,-STACKFRAMESIZE(r1)
> -	std	r3,STK_PARAM(R3)(r1)
> -	std	r4,STK_PARAM(R4)(r1)
> -	li	r3,H_HAL_TAKEOVER
> -	li	r4,H_HAL_TAKEOVER_QUERY_MAGIC
> -	HVSC
> -	addi	r1,r1,STACKFRAMESIZE
> -	ld	r10,STK_PARAM(R3)(r1)
> -	std	r4,0(r10)
> -	ld	r10,STK_PARAM(R4)(r1)
> -	std	r5,0(r10)
> -	lwz	r0,8(r1)
> -	mtcrf	0xff,r0
> -	blr
> -
> -_GLOBAL(opal_do_takeover)
> -	mfcr	r0
> -	stw	r0,8(r1)
> -	mflr	r0
> -	std	r0,16(r1)
> -	bl	__opal_do_takeover
> -	ld	r0,16(r1)
> -	mtlr	r0
> -	lwz	r0,8(r1)
> -	mtcrf	0xff,r0
> -	blr
> -
> -__opal_do_takeover:
> -	ld	r4,0(r3)
> -	ld	r5,0x8(r3)
> -	ld	r6,0x10(r3)
> -	ld	r7,0x18(r3)
> -	ld	r8,0x20(r3)
> -	ld	r9,0x28(r3)
> -	ld	r10,0x30(r3)
> -	ld	r11,0x38(r3)
> -	li	r3,H_HAL_TAKEOVER
> -	HVSC
> -	blr
> -
> -	.globl opal_secondary_entry
> -opal_secondary_entry:
> -	mr	r31,r3
> -	mfmsr	r11
> -	li	r12,(MSR_SF | MSR_ISF)@highest
> -	sldi	r12,r12,48
> -	or	r11,r11,r12
> -	mtmsrd	r11
> -	isync
> -	mfspr	r4,SPRN_PIR
> -	std	r4,0(r3)
> -1:	HMT_LOW
> -	ld	r4,8(r3)
> -	cmpli	cr0,r4,0
> -	beq	1b
> -	HMT_MEDIUM
> -1:	addi	r3,r31,16
> -	bl	__opal_do_takeover
> -	b	1b
> -
> -_GLOBAL(opal_enter_rtas)
> -	mflr	r0
> -	std	r0,16(r1)
> -        stdu	r1,-PROM_FRAME_SIZE(r1)	/* Save SP and create stack space */
> -
> -	/* Because PROM is running in 32b mode, it clobbers the high order half
> -	 * of all registers that it saves.  We therefore save those registers
> -	 * PROM might touch to the stack.  (r0, r3-r13 are caller saved)
> -	*/
> -	SAVE_GPR(2, r1)
> -	SAVE_GPR(13, r1)
> -	SAVE_8GPRS(14, r1)
> -	SAVE_10GPRS(22, r1)
> -	mfcr	r10
> -	mfmsr	r11
> -	std	r10,_CCR(r1)
> -	std	r11,_MSR(r1)
> -
> -	/* Get the PROM entrypoint */
> -	mtlr	r5
> -
> -	/* Switch MSR to 32 bits mode
> -	 */
> -        li      r12,1
> -        rldicr  r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
> -        andc    r11,r11,r12
> -        li      r12,1
> -        rldicr  r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
> -        andc    r11,r11,r12
> -        mtmsrd  r11
> -        isync
> -
> -	/* Enter RTAS here... */
> -	blrl
> -
> -	/* Just make sure that r1 top 32 bits didn't get
> -	 * corrupt by OF
> -	 */
> -	rldicl	r1,r1,0,32
> -
> -	/* Restore the MSR (back to 64 bits) */
> -	ld	r0,_MSR(r1)
> -	MTMSRD(r0)
> -        isync
> -
> -	/* Restore other registers */
> -	REST_GPR(2, r1)
> -	REST_GPR(13, r1)
> -	REST_8GPRS(14, r1)
> -	REST_10GPRS(22, r1)
> -	ld	r4,_CCR(r1)
> -	mtcr	r4
> -
> -        addi	r1,r1,PROM_FRAME_SIZE
> -	ld	r0,16(r1)
> -	mtlr    r0
> -	blr