diff mbox series

[v5,6/9] hw/slw: split P8 specific code into its own file

Message ID 20211220122252.986542-7-npiggin@gmail.com
State Accepted
Headers show
Series hwprobe patches | expand

Commit Message

Nicholas Piggin Dec. 20, 2021, 12:22 p.m. UTC
POWER8 support is large and significantly different than P9/10 code.
This change prepares to make P8 support configurable.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 core/fast-reboot.c |   1 +
 core/init.c        |   1 +
 hw/Makefile.inc    |   2 +-
 hw/imc.c           |   1 +
 hw/nx.c            |   1 +
 hw/slw-p8.c        | 508 +++++++++++++++++++++++++++++++++++++++++++++
 hw/slw.c           | 491 +------------------------------------------
 hw/xive.c          |   1 +
 hw/xive2.c         |   1 +
 include/skiboot.h  |  12 --
 include/slw.h      |  48 +++++
 11 files changed, 574 insertions(+), 493 deletions(-)
 create mode 100644 hw/slw-p8.c
 create mode 100644 include/slw.h

Comments

Cédric Le Goater Jan. 3, 2022, 3:32 p.m. UTC | #1
On 12/20/21 13:22, Nicholas Piggin wrote:
> POWER8 support is large and significantly different than P9/10 code.
> This change prepares to make P8 support configurable.
> 
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>


Thanks for doing this cleanup. Looks good to me.

C.


> ---
>   core/fast-reboot.c |   1 +
>   core/init.c        |   1 +
>   hw/Makefile.inc    |   2 +-
>   hw/imc.c           |   1 +
>   hw/nx.c            |   1 +
>   hw/slw-p8.c        | 508 +++++++++++++++++++++++++++++++++++++++++++++
>   hw/slw.c           | 491 +------------------------------------------
>   hw/xive.c          |   1 +
>   hw/xive2.c         |   1 +
>   include/skiboot.h  |  12 --
>   include/slw.h      |  48 +++++
>   11 files changed, 574 insertions(+), 493 deletions(-)
>   create mode 100644 hw/slw-p8.c
>   create mode 100644 include/slw.h
> 
> diff --git a/core/fast-reboot.c b/core/fast-reboot.c
> index 2696348af..fedfa88cc 100644
> --- a/core/fast-reboot.c
> +++ b/core/fast-reboot.c
> @@ -6,6 +6,7 @@
>    */
>   
>   #include <skiboot.h>
> +#include <slw.h>
>   #include <cpu.h>
>   #include <console.h>
>   #include <fsp.h>
> diff --git a/core/init.c b/core/init.c
> index c3e0c494d..deead5ecc 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -6,6 +6,7 @@
>    */
>   
>   #include <skiboot.h>
> +#include <slw.h>
>   #include <psi.h>
>   #include <chiptod.h>
>   #include <nx.h>
> diff --git a/hw/Makefile.inc b/hw/Makefile.inc
> index 8f509739d..7327cec35 100644
> --- a/hw/Makefile.inc
> +++ b/hw/Makefile.inc
> @@ -10,7 +10,7 @@ HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o
>   HW_OBJS += occ-sensor.o vas.o dio-p9.o lpc-port80h.o cache-p9.o
>   HW_OBJS += npu-opal.o ocmb.o xive2.o pau.o pau-hw-procedures.o
>   ifeq ($(CONFIG_P8),1)
> -HW_OBJS += phb3.o sbe-p8.o
> +HW_OBJS += phb3.o sbe-p8.o slw-p8.o
>   endif
>   HW=hw/built-in.a
>   
> diff --git a/hw/imc.c b/hw/imc.c
> index cbd68edc4..97e0809f0 100644
> --- a/hw/imc.c
> +++ b/hw/imc.c
> @@ -8,6 +8,7 @@
>   
>   #define pr_fmt(fmt)  "IMC: " fmt
>   #include <skiboot.h>
> +#include <slw.h>
>   #include <xscom.h>
>   #include <imc.h>
>   #include <chip.h>
> diff --git a/hw/nx.c b/hw/nx.c
> index fdadf53c7..13c681b2c 100644
> --- a/hw/nx.c
> +++ b/hw/nx.c
> @@ -6,6 +6,7 @@
>    */
>   
>   #include <skiboot.h>
> +#include <slw.h>
>   #include <xscom.h>
>   #include <io.h>
>   #include <cpu.h>
> diff --git a/hw/slw-p8.c b/hw/slw-p8.c
> new file mode 100644
> index 000000000..0a27a8fcc
> --- /dev/null
> +++ b/hw/slw-p8.c
> @@ -0,0 +1,508 @@
> +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
> +
> +#include <skiboot.h>
> +#include <slw.h>
> +#include <xscom.h>
> +#include <xscom-p8-regs.h>
> +#include <cpu.h>
> +#include <chip.h>
> +#include <interrupts.h>
> +#include <timebase.h>
> +#include <errorlog.h>
> +#include <libfdt/libfdt.h>
> +#include <opal-api.h>
> +#include <sbe-p8.h>
> +
> +#include <p8_pore_table_gen_api.H>
> +#include <sbe_xip_image.h>
> +
> +/*
> + * It would be nice to be able to define non-static log entry types and share
> + * these with slw.c
> + */
> +DEFINE_LOG_ENTRY(OPAL_RC_SLW_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
> +		 OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
> +		 OPAL_NA);
> +
> +DEFINE_LOG_ENTRY(OPAL_RC_SLW_SET, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
> +		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
> +		 OPAL_NA);
> +
> +DEFINE_LOG_ENTRY(OPAL_RC_SLW_GET, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
> +		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
> +		 OPAL_NA);
> +
> +DEFINE_LOG_ENTRY(OPAL_RC_SLW_REG, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
> +		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
> +		 OPAL_NA);
> +
> +static bool slw_general_init(struct proc_chip *chip, struct cpu_thread *c)
> +{
> +	uint32_t core = pir_to_core_id(c->pir);
> +	uint64_t tmp;
> +	int rc;
> +
> +	/* PowerManagement GP0 clear PM_DISABLE */
> +	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> +				"SLW: Failed to read PM_GP0\n");
> +		return false;
> +	}
> +	tmp = tmp & ~0x8000000000000000ULL;
> +	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), tmp);
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> +				"SLW: Failed to write PM_GP0\n");
> +		return false;
> +	}
> +	prlog(PR_TRACE, "SLW: PMGP0 set to 0x%016llx\n", tmp);
> +
> +	/* Read back for debug */
> +	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
> +	if (rc)
> +		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> +				 "SLW: Failed to re-read PM_GP0. Continuing...\n");
> +
> +	prlog(PR_TRACE, "SLW: PMGP0 read   0x%016llx\n", tmp);
> +
> +	return true;
> +}
> +
> +static bool slw_set_overrides(struct proc_chip *chip, struct cpu_thread *c)
> +{
> +	uint32_t core = pir_to_core_id(c->pir);
> +	int rc;
> +
> +	rc = xscom_write(chip->id,
> +			 XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SPECIAL_WAKEUP_PHYP),
> +			 0);
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_SET),
> +			"SLW: Failed to write PM_SPECIAL_WAKEUP_PHYP\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +static bool slw_set_idle_mode(struct proc_chip *chip, struct cpu_thread *c)
> +{
> +	uint32_t core = pir_to_core_id(c->pir);
> +	uint64_t tmp;
> +	int rc;
> +
> +	/*
> +	 * PM GP1 allows fast/deep mode to be selected independently for sleep
> +	 * and winkle. Init PM GP1 so that sleep happens in fast mode and
> +	 * winkle happens in deep mode.
> +	 * Make use of the OR XSCOM for this since the OCC might be manipulating
> +	 * the PM_GP1 register as well. Before doing this ensure that the bits
> +	 * managing idle states are cleared so as to override any bits set at
> +	 * init time.
> +	 */
> +
> +	tmp = ~EX_PM_GP1_SLEEP_WINKLE_MASK;
> +	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_CLEAR_GP1),
> +			 tmp);
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_SET),
> +						"SLW: Failed to write PM_GP1\n");
> +		return false;
> +	}
> +
> +	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SET_GP1),
> +			 EX_PM_SETUP_GP1_FAST_SLEEP_DEEP_WINKLE);
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_SET),
> +						"SLW: Failed to write PM_GP1\n");
> +		return false;
> +	}
> +
> +	/* Read back for debug */
> +	xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP1), &tmp);
> +	prlog(PR_TRACE, "SLW: PMGP1 read   0x%016llx\n", tmp);
> +	return true;
> +}
> +
> +static bool slw_get_idle_state_history(struct proc_chip *chip, struct cpu_thread *c)
> +{
> +	uint32_t core = pir_to_core_id(c->pir);
> +	uint64_t tmp;
> +	int rc;
> +
> +	/* Cleanup history */
> +	rc = xscom_read(chip->id,
> +		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
> +		   &tmp);
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_GET),
> +			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
> +		return false;
> +	}
> +
> +	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old1)\n",
> +	    chip->id, core, tmp);
> +
> +	rc = xscom_read(chip->id,
> +		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
> +		   &tmp);
> +
> +	if (rc) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_GET),
> +			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
> +		return false;
> +	}
> +
> +	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old2)\n",
> +	    chip->id, core, tmp);
> +
> +	return true;
> +}
> +
> +static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c)
> +{
> +	prlog(PR_TRACE, "FASTSLEEP: Prepare core %x:%x\n",
> +	    chip->id, pir_to_core_id(c->pir));
> +
> +	if(!slw_general_init(chip, c))
> +		return false;
> +	if(!slw_set_overrides(chip, c))
> +		return false;
> +	if(!slw_set_idle_mode(chip, c))
> +		return false;
> +	if(!slw_get_idle_state_history(chip, c))
> +		return false;
> +
> +	return true;
> +
> +}
> +
> +static struct cpu_idle_states nap_only_cpu_idle_states[] = {
> +	{ /* nap */
> +		.name = "nap",
> +		.latency_ns = 4000,
> +		.residency_ns = 100000,
> +		.flags = 0*OPAL_PM_DEC_STOP \
> +		       | 0*OPAL_PM_TIMEBASE_STOP  \
> +		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> +		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
> +		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
> +		       | 1*OPAL_PM_NAP_ENABLED \
> +		       | 0*OPAL_PM_SLEEP_ENABLED \
> +		       | 0*OPAL_PM_WINKLE_ENABLED \
> +		       | 0*OPAL_USE_PMICR,
> +		.pm_ctrl_reg_val = 0,
> +		.pm_ctrl_reg_mask = 0 },
> +};
> +
> +static struct cpu_idle_states power8_cpu_idle_states[] = {
> +	{ /* nap */
> +		.name = "nap",
> +		.latency_ns = 4000,
> +		.residency_ns = 100000,
> +		.flags = 0*OPAL_PM_DEC_STOP \
> +		       | 0*OPAL_PM_TIMEBASE_STOP  \
> +		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> +		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
> +		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
> +		       | 1*OPAL_PM_NAP_ENABLED \
> +		       | 0*OPAL_USE_PMICR,
> +		.pm_ctrl_reg_val = 0,
> +		.pm_ctrl_reg_mask = 0 },
> +	{ /* fast sleep (with workaround) */
> +		.name = "fastsleep_",
> +		.latency_ns = 40000,
> +		.residency_ns = 300000000,
> +		.flags = 1*OPAL_PM_DEC_STOP \
> +		       | 1*OPAL_PM_TIMEBASE_STOP  \
> +		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> +		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
> +		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
> +		       | 1*OPAL_PM_SLEEP_ENABLED_ER1 \
> +		       | 0*OPAL_USE_PMICR, /* Not enabled until deep
> +						states are available */
> +		.pm_ctrl_reg_val = OPAL_PM_FASTSLEEP_PMICR,
> +		.pm_ctrl_reg_mask = OPAL_PM_SLEEP_PMICR_MASK },
> +	{ /* Winkle */
> +		.name = "winkle",
> +		.latency_ns = 10000000,
> +		.residency_ns = 1000000000, /* Educated guess (not measured).
> +					     * Winkle is not currently used by
> +					     * linux cpuidle subsystem so we
> +					     * don't have real world user.
> +					     * However, this should be roughly
> +					     * accurate for when linux does
> +					     * use it. */
> +		.flags = 1*OPAL_PM_DEC_STOP \
> +		       | 1*OPAL_PM_TIMEBASE_STOP  \
> +		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> +		       | 1*OPAL_PM_LOSE_HYP_CONTEXT \
> +		       | 1*OPAL_PM_LOSE_FULL_CONTEXT \
> +		       | 1*OPAL_PM_WINKLE_ENABLED \
> +		       | 0*OPAL_USE_PMICR, /* Currently choosing deep vs
> +						fast via EX_PM_GP1 reg */
> +		.pm_ctrl_reg_val = 0,
> +		.pm_ctrl_reg_mask = 0 },
> +};
> +
> +void find_cpu_idle_state_properties_p8(struct cpu_idle_states **states,
> +				       int *nr_states, bool *can_sleep)
> +{
> +	struct proc_chip *chip;
> +
> +	chip = next_chip(NULL);
> +	assert(chip);
> +
> +	*can_sleep = true;
> +
> +	if (chip->type == PROC_CHIP_P8_MURANO ||
> +	    chip->type == PROC_CHIP_P8_VENICE ||
> +	    chip->type == PROC_CHIP_P8_NAPLES) {
> +		const struct dt_property *p;
> +
> +		p = dt_find_property(dt_root, "ibm,enabled-idle-states");
> +		if (p)
> +			prlog(PR_NOTICE,
> +			      "SLW: HB-provided idle states property found\n");
> +		*states = power8_cpu_idle_states;
> +		*nr_states = ARRAY_SIZE(power8_cpu_idle_states);
> +
> +		/* Check if hostboot say we can sleep */
> +		if (!p || !dt_prop_find_string(p, "fast-sleep")) {
> +			prlog(PR_WARNING, "SLW: Sleep not enabled by HB"
> +			      " on this platform\n");
> +			*can_sleep = false;
> +		}
> +
> +		/* Clip to NAP only on Murano and Venice DD1.x */
> +		if ((chip->type == PROC_CHIP_P8_MURANO ||
> +		     chip->type == PROC_CHIP_P8_VENICE) &&
> +		    chip->ec_level < 0x20) {
> +			prlog(PR_NOTICE, "SLW: Sleep not enabled on P8 DD1.x\n");
> +			*can_sleep = false;
> +		}
> +
> +	} else {
> +		*states = nap_only_cpu_idle_states;
> +		*nr_states = ARRAY_SIZE(nap_only_cpu_idle_states);
> +	}
> +}
> +
> +static void slw_patch_regs(struct proc_chip *chip)
> +{
> +	struct cpu_thread *c;
> +	void *image = (void *)chip->slw_base;
> +	int rc;
> +
> +	for_each_available_cpu(c) {
> +		if (c->chip_id != chip->id)
> +			continue;
> +
> +		/* Clear HRMOR */
> +		rc =  p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
> +					       P8_SPR_HRMOR, 0,
> +					       cpu_get_core_index(c),
> +					       cpu_get_thread_index(c));
> +		if (rc) {
> +			log_simple_error(&e_info(OPAL_RC_SLW_REG),
> +				"SLW: Failed to set HRMOR for CPU %x\n",
> +				c->pir);
> +		}
> +
> +		/* XXX Add HIDs etc... */
> +	}
> +}
> +
> +static bool  slw_image_check_p8(struct proc_chip *chip)
> +{
> +	int64_t rc;
> +
> +	prlog(PR_DEBUG, "SLW: slw_check chip 0x%x\n", chip->id);
> +	if (!chip->slw_base) {
> +		prerror("SLW: No image found !\n");
> +		return false;
> +	}
> +
> +	/* Check actual image size */
> +	rc = sbe_xip_get_scalar((void *)chip->slw_base, "image_size",
> +				&chip->slw_image_size);
> +	if (rc != 0) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> +			"SLW: Error %lld reading SLW image size\n", rc);
> +		/* XXX Panic ? */
> +		chip->slw_base = 0;
> +		chip->slw_bar_size = 0;
> +		chip->slw_image_size = 0;
> +		return false;
> +	}
> +	prlog(PR_DEBUG, "SLW: Image size from image: 0x%llx\n",
> +	      chip->slw_image_size);
> +
> +	if (chip->slw_image_size > chip->slw_bar_size) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> +			"SLW: Built-in image size larger than BAR size !\n");
> +		/* XXX Panic ? */
> +		return false;
> +	}
> +	return true;
> +
> +}
> +
> +static void slw_late_init_p8(struct proc_chip *chip)
> +{
> +
> +	prlog(PR_DEBUG, "SLW: late Init chip 0x%x\n", chip->id);
> +
> +	/* Patch SLW image */
> +        slw_patch_regs(chip);
> +
> +}
> +static void slw_init_chip_p8(struct proc_chip *chip)
> +{
> +	struct cpu_thread *c;
> +
> +	prlog(PR_DEBUG, "SLW: Init chip 0x%x\n", chip->id);
> +	/* At power ON setup inits for fast-sleep */
> +	for_each_available_core_in_chip(c, chip->id) {
> +		idle_prepare_core(chip, c);
> +	}
> +}
> +
> +/* Workarounds while entering fast-sleep */
> +
> +static void fast_sleep_enter(void)
> +{
> +	uint32_t core = pir_to_core_id(this_cpu()->pir);
> +	uint32_t chip_id = this_cpu()->chip_id;
> +	struct cpu_thread *primary_thread;
> +	uint64_t tmp;
> +	int rc;
> +
> +	primary_thread = this_cpu()->primary;
> +
> +	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> +			&tmp);
> +	if (rc) {
> +		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(1):"
> +		      " rc=%d chip_id=%d core=%d\n",
> +		      rc, chip_id, core);
> +		return;
> +	}
> +
> +	primary_thread->save_l2_fir_action1 = tmp;
> +	primary_thread->in_fast_sleep = true;
> +
> +	tmp = tmp & ~0x0200000000000000ULL;
> +	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> +			 tmp);
> +	if (rc) {
> +		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(2):"
> +		      " rc=%d chip_id=%d core=%d\n",
> +		      rc, chip_id, core);
> +		return;
> +	}
> +	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> +			&tmp);
> +	if (rc) {
> +		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(3):"
> +		      " rc=%d chip_id=%d core=%d\n",
> +		      rc, chip_id, core);
> +		return;
> +	}
> +
> +}
> +
> +/* Workarounds while exiting fast-sleep */
> +
> +void fast_sleep_exit(void)
> +{
> +	uint32_t core = pir_to_core_id(this_cpu()->pir);
> +	uint32_t chip_id = this_cpu()->chip_id;
> +	struct cpu_thread *primary_thread;
> +	int rc;
> +
> +	primary_thread = this_cpu()->primary;
> +	primary_thread->in_fast_sleep = false;
> +
> +	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> +			primary_thread->save_l2_fir_action1);
> +	if (rc) {
> +		prlog(PR_WARNING, "fast_sleep_exit XSCOM failed:"
> +		      " rc=%d chip_id=%d core=%d\n",
> +		      rc, chip_id, core);
> +		return;
> +	}
> +}
> +
> +/*
> + * Setup and cleanup method for fast-sleep workarounds
> + * state = 1 fast-sleep
> + * enter = 1 Enter state
> + * exit  = 0 Exit state
> + */
> +
> +static int64_t opal_config_cpu_idle_state(uint64_t state, uint64_t enter)
> +{
> +	/* Only fast-sleep for now */
> +	if (state != 1)
> +		return OPAL_PARAMETER;	
> +
> +	switch(enter) {
> +	case 1:
> +		fast_sleep_enter();
> +		break;
> +	case 0:
> +		fast_sleep_exit();
> +		break;
> +	default:
> +		return OPAL_PARAMETER;
> +	}
> +
> +	return OPAL_SUCCESS;
> +}
> +
> +opal_call(OPAL_CONFIG_CPU_IDLE_STATE, opal_config_cpu_idle_state, 2);
> +
> +int64_t opal_slw_set_reg_p8(struct cpu_thread *c, struct proc_chip *chip,
> +			    uint64_t sprn, uint64_t val)
> +{
> +	int spr_is_supported = 0;
> +	void *image;
> +	int i;
> +	int rc;
> +
> +	/* Check of the SPR is supported by libpore */
> +	for (i = 0; i < SLW_SPR_REGS_SIZE ; i++)  {
> +		if (sprn == SLW_SPR_REGS[i].value)  {
> +			spr_is_supported = 1;
> +			break;
> +		}
> +	}
> +	if (!spr_is_supported) {
> +		log_simple_error(&e_info(OPAL_RC_SLW_REG),
> +		"SLW: Trying to set unsupported spr for CPU %x\n",
> +			c->pir);
> +		return OPAL_UNSUPPORTED;
> +	}
> +	image = (void *)chip->slw_base;
> +	rc = p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
> +				      sprn, val,
> +				      cpu_get_core_index(c),
> +				      cpu_get_thread_index(c));
> +	return rc;
> +}
> +
> +void slw_p8_init(void)
> +{
> +	struct proc_chip *chip;
> +
> +	for_each_chip(chip) {
> +		slw_init_chip_p8(chip);
> +		if (slw_image_check_p8(chip))
> +			wakeup_engine_state = WAKEUP_ENGINE_PRESENT;
> +		if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT)
> +			slw_late_init_p8(chip);
> +	}
> +	p8_sbe_init_timer();
> +}
> diff --git a/hw/slw.c b/hw/slw.c
> index bc53960b7..6d7c8619c 100644
> --- a/hw/slw.c
> +++ b/hw/slw.c
> @@ -7,8 +7,8 @@
>    */
>   
>   #include <skiboot.h>
> +#include <slw.h>
>   #include <xscom.h>
> -#include <xscom-p8-regs.h>
>   #include <xscom-p9-regs.h>
>   #include <xscom-p10-regs.h>
>   #include <io.h>
> @@ -22,12 +22,10 @@
>   #include <libfdt/libfdt.h>
>   #include <opal-api.h>
>   #include <nvram.h>
> -#include <sbe-p8.h>
>   #include <xive.h>
>   
>   #include <p10_stop_api.H>
> -#include <p8_pore_table_gen_api.H>
> -#include <sbe_xip_image.h>
> +//#include <sbe_xip_image.h>
>   
>   enum wakeup_engine_states wakeup_engine_state = WAKEUP_ENGINE_NOT_PRESENT;
>   bool has_deep_states = false;
> @@ -40,158 +38,6 @@ DEFINE_LOG_ENTRY(OPAL_RC_SLW_REG, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
>   		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
>   		 OPAL_NA);
>   
> -#ifdef CONFIG_P8
> -DEFINE_LOG_ENTRY(OPAL_RC_SLW_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
> -		 OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
> -		 OPAL_NA);
> -
> -DEFINE_LOG_ENTRY(OPAL_RC_SLW_GET, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
> -		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
> -		 OPAL_NA);
> -
> -static bool slw_general_init(struct proc_chip *chip, struct cpu_thread *c)
> -{
> -	uint32_t core = pir_to_core_id(c->pir);
> -	uint64_t tmp;
> -	int rc;
> -
> -	/* PowerManagement GP0 clear PM_DISABLE */
> -	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
> -	if (rc) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> -				"SLW: Failed to read PM_GP0\n");
> -		return false;
> -	}
> -	tmp = tmp & ~0x8000000000000000ULL;
> -	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), tmp);
> -	if (rc) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> -				"SLW: Failed to write PM_GP0\n");
> -		return false;
> -	}
> -	prlog(PR_TRACE, "SLW: PMGP0 set to 0x%016llx\n", tmp);
> -
> -	/* Read back for debug */
> -	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
> -	if (rc)
> -		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> -				 "SLW: Failed to re-read PM_GP0. Continuing...\n");
> -
> -	prlog(PR_TRACE, "SLW: PMGP0 read   0x%016llx\n", tmp);
> -
> -	return true;
> -}
> -
> -static bool slw_set_overrides(struct proc_chip *chip, struct cpu_thread *c)
> -{
> -	uint32_t core = pir_to_core_id(c->pir);
> -	int rc;
> -
> -	rc = xscom_write(chip->id,
> -			 XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SPECIAL_WAKEUP_PHYP),
> -			 0);
> -	if (rc) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_SET),
> -			"SLW: Failed to write PM_SPECIAL_WAKEUP_PHYP\n");
> -		return false;
> -	}
> -
> -	return true;
> -}
> -
> -static bool slw_set_idle_mode(struct proc_chip *chip, struct cpu_thread *c)
> -{
> -	uint32_t core = pir_to_core_id(c->pir);
> -	uint64_t tmp;
> -	int rc;
> -
> -	/*
> -	 * PM GP1 allows fast/deep mode to be selected independently for sleep
> -	 * and winkle. Init PM GP1 so that sleep happens in fast mode and
> -	 * winkle happens in deep mode.
> -	 * Make use of the OR XSCOM for this since the OCC might be manipulating
> -	 * the PM_GP1 register as well. Before doing this ensure that the bits
> -	 * managing idle states are cleared so as to override any bits set at
> -	 * init time.
> -	 */
> -
> -	tmp = ~EX_PM_GP1_SLEEP_WINKLE_MASK;
> -	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_CLEAR_GP1),
> -			 tmp);
> -	if (rc) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_SET),
> -						"SLW: Failed to write PM_GP1\n");
> -		return false;
> -	}
> -
> -	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SET_GP1),
> -			 EX_PM_SETUP_GP1_FAST_SLEEP_DEEP_WINKLE);
> -	if (rc) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_SET),
> -						"SLW: Failed to write PM_GP1\n");
> -		return false;
> -	}
> -
> -	/* Read back for debug */
> -	xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP1), &tmp);
> -	prlog(PR_TRACE, "SLW: PMGP1 read   0x%016llx\n", tmp);
> -	return true;
> -}
> -
> -static bool slw_get_idle_state_history(struct proc_chip *chip, struct cpu_thread *c)
> -{
> -	uint32_t core = pir_to_core_id(c->pir);
> -	uint64_t tmp;
> -	int rc;
> -
> -	/* Cleanup history */
> -	rc = xscom_read(chip->id,
> -		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
> -		   &tmp);
> -	if (rc) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_GET),
> -			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
> -		return false;
> -	}
> -
> -	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old1)\n",
> -	    chip->id, core, tmp);
> -
> -	rc = xscom_read(chip->id,
> -		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
> -		   &tmp);
> -
> -	if (rc) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_GET),
> -			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
> -		return false;
> -	}
> -
> -	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old2)\n",
> -	    chip->id, core, tmp);
> -
> -	return true;
> -}
> -
> -static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c)
> -{
> -	prlog(PR_TRACE, "FASTSLEEP: Prepare core %x:%x\n",
> -	    chip->id, pir_to_core_id(c->pir));
> -
> -	if(!slw_general_init(chip, c))
> -		return false;
> -	if(!slw_set_overrides(chip, c))
> -		return false;
> -	if(!slw_set_idle_mode(chip, c))
> -		return false;
> -	if(!slw_get_idle_state_history(chip, c))
> -		return false;
> -
> -	return true;
> -
> -}
> -#endif
> -
>   static bool slw_set_overrides_p10(struct proc_chip *chip, struct cpu_thread *c)
>   {
>   	uint64_t tmp;
> @@ -245,89 +91,6 @@ static bool slw_set_overrides_p9(struct proc_chip *chip, struct cpu_thread *c)
>   	return true;
>   }
>   
> -/* Define device-tree fields */
> -#define MAX_NAME_LEN	16
> -struct cpu_idle_states {
> -	char name[MAX_NAME_LEN];
> -	u32 latency_ns;
> -	u32 residency_ns;
> -	/*
> -	 * Register value/mask used to select different idle states.
> -	 * PMICR in POWER8 and PSSCR in POWER9
> -	 */
> -	u64 pm_ctrl_reg_val;
> -	u64 pm_ctrl_reg_mask;
> -	u32 flags;
> -};
> -
> -static struct cpu_idle_states nap_only_cpu_idle_states[] = {
> -	{ /* nap */
> -		.name = "nap",
> -		.latency_ns = 4000,
> -		.residency_ns = 100000,
> -		.flags = 0*OPAL_PM_DEC_STOP \
> -		       | 0*OPAL_PM_TIMEBASE_STOP  \
> -		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> -		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
> -		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
> -		       | 1*OPAL_PM_NAP_ENABLED \
> -		       | 0*OPAL_PM_SLEEP_ENABLED \
> -		       | 0*OPAL_PM_WINKLE_ENABLED \
> -		       | 0*OPAL_USE_PMICR,
> -		.pm_ctrl_reg_val = 0,
> -		.pm_ctrl_reg_mask = 0 },
> -};
> -
> -static struct cpu_idle_states power8_cpu_idle_states[] = {
> -	{ /* nap */
> -		.name = "nap",
> -		.latency_ns = 4000,
> -		.residency_ns = 100000,
> -		.flags = 0*OPAL_PM_DEC_STOP \
> -		       | 0*OPAL_PM_TIMEBASE_STOP  \
> -		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> -		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
> -		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
> -		       | 1*OPAL_PM_NAP_ENABLED \
> -		       | 0*OPAL_USE_PMICR,
> -		.pm_ctrl_reg_val = 0,
> -		.pm_ctrl_reg_mask = 0 },
> -	{ /* fast sleep (with workaround) */
> -		.name = "fastsleep_",
> -		.latency_ns = 40000,
> -		.residency_ns = 300000000,
> -		.flags = 1*OPAL_PM_DEC_STOP \
> -		       | 1*OPAL_PM_TIMEBASE_STOP  \
> -		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> -		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
> -		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
> -		       | 1*OPAL_PM_SLEEP_ENABLED_ER1 \
> -		       | 0*OPAL_USE_PMICR, /* Not enabled until deep
> -						states are available */
> -		.pm_ctrl_reg_val = OPAL_PM_FASTSLEEP_PMICR,
> -		.pm_ctrl_reg_mask = OPAL_PM_SLEEP_PMICR_MASK },
> -	{ /* Winkle */
> -		.name = "winkle",
> -		.latency_ns = 10000000,
> -		.residency_ns = 1000000000, /* Educated guess (not measured).
> -					     * Winkle is not currently used by
> -					     * linux cpuidle subsystem so we
> -					     * don't have real world user.
> -					     * However, this should be roughly
> -					     * accurate for when linux does
> -					     * use it. */
> -		.flags = 1*OPAL_PM_DEC_STOP \
> -		       | 1*OPAL_PM_TIMEBASE_STOP  \
> -		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
> -		       | 1*OPAL_PM_LOSE_HYP_CONTEXT \
> -		       | 1*OPAL_PM_LOSE_FULL_CONTEXT \
> -		       | 1*OPAL_PM_WINKLE_ENABLED \
> -		       | 0*OPAL_USE_PMICR, /* Currently choosing deep vs
> -						fast via EX_PM_GP1 reg */
> -		.pm_ctrl_reg_val = 0,
> -		.pm_ctrl_reg_mask = 0 },
> -};
> -
>   /*
>    * cpu_idle_states for key idle states of POWER9 that we want to
>    * exploit.
> @@ -796,9 +559,9 @@ static void slw_late_init_p10(struct proc_chip *chip)
>   void add_cpu_idle_state_properties(void)
>   {
>   	struct dt_node *power_mgt;
> -	struct cpu_idle_states *states;
> +	struct cpu_idle_states *states = NULL;
>   	struct proc_chip *chip;
> -	int nr_states;
> +	int nr_states = 0;
>   
>   	bool can_sleep = true;
>   	bool has_stop_inst = false;
> @@ -897,39 +660,12 @@ void add_cpu_idle_state_properties(void)
>   			}
>   			if (wakeup_engine_state != WAKEUP_ENGINE_PRESENT)
>   				has_deep_states = false;
> -	} else if (chip->type == PROC_CHIP_P8_MURANO ||
> -	    chip->type == PROC_CHIP_P8_VENICE ||
> -	    chip->type == PROC_CHIP_P8_NAPLES) {
> -		const struct dt_property *p;
> -
> -		p = dt_find_property(dt_root, "ibm,enabled-idle-states");
> -		if (p)
> -			prlog(PR_NOTICE,
> -			      "SLW: HB-provided idle states property found\n");
> -		states = power8_cpu_idle_states;
> -		nr_states = ARRAY_SIZE(power8_cpu_idle_states);
> -
> -		/* Check if hostboot say we can sleep */
> -		if (!p || !dt_prop_find_string(p, "fast-sleep")) {
> -			prlog(PR_WARNING, "SLW: Sleep not enabled by HB"
> -			      " on this platform\n");
> -			can_sleep = false;
> -		}
> -
> -		/* Clip to NAP only on Murano and Venice DD1.x */
> -		if ((chip->type == PROC_CHIP_P8_MURANO ||
> -		     chip->type == PROC_CHIP_P8_VENICE) &&
> -		    chip->ec_level < 0x20) {
> -			prlog(PR_NOTICE, "SLW: Sleep not enabled on P8 DD1.x\n");
> -			can_sleep = false;
> -		}
> -
> +#ifdef CONFIG_P8
>   	} else {
> -		states = nap_only_cpu_idle_states;
> -		nr_states = ARRAY_SIZE(nap_only_cpu_idle_states);
> +		find_cpu_idle_state_properties_p8(&states, &nr_states, &can_sleep);
> +#endif
>   	}
>   
> -
>   	/*
>   	 * Currently we can't append strings and cells to dt properties.
>   	 * So create buffers to which you can append values, then create
> @@ -1112,183 +848,6 @@ static bool  slw_image_check_p9(struct proc_chip *chip)
>   
>   }
>   
> -#ifdef CONFIG_P8
> -static void slw_patch_regs(struct proc_chip *chip)
> -{
> -	struct cpu_thread *c;
> -	void *image = (void *)chip->slw_base;
> -	int rc;
> -
> -	for_each_available_cpu(c) {
> -		if (c->chip_id != chip->id)
> -			continue;
> -
> -		/* Clear HRMOR */
> -		rc =  p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
> -					       P8_SPR_HRMOR, 0,
> -					       cpu_get_core_index(c),
> -					       cpu_get_thread_index(c));
> -		if (rc) {
> -			log_simple_error(&e_info(OPAL_RC_SLW_REG),
> -				"SLW: Failed to set HRMOR for CPU %x\n",
> -				c->pir);
> -		}
> -
> -		/* XXX Add HIDs etc... */
> -	}
> -}
> -
> -static bool  slw_image_check_p8(struct proc_chip *chip)
> -{
> -	int64_t rc;
> -
> -	prlog(PR_DEBUG, "SLW: slw_check chip 0x%x\n", chip->id);
> -	if (!chip->slw_base) {
> -		prerror("SLW: No image found !\n");
> -		return false;
> -	}
> -
> -	/* Check actual image size */
> -	rc = sbe_xip_get_scalar((void *)chip->slw_base, "image_size",
> -				&chip->slw_image_size);
> -	if (rc != 0) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> -			"SLW: Error %lld reading SLW image size\n", rc);
> -		/* XXX Panic ? */
> -		chip->slw_base = 0;
> -		chip->slw_bar_size = 0;
> -		chip->slw_image_size = 0;
> -		return false;
> -	}
> -	prlog(PR_DEBUG, "SLW: Image size from image: 0x%llx\n",
> -	      chip->slw_image_size);
> -
> -	if (chip->slw_image_size > chip->slw_bar_size) {
> -		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
> -			"SLW: Built-in image size larger than BAR size !\n");
> -		/* XXX Panic ? */
> -		return false;
> -	}
> -	return true;
> -
> -}
> -
> -static void slw_late_init_p8(struct proc_chip *chip)
> -{
> -
> -	prlog(PR_DEBUG, "SLW: late Init chip 0x%x\n", chip->id);
> -
> -	/* Patch SLW image */
> -        slw_patch_regs(chip);
> -
> -}
> -static void slw_init_chip_p8(struct proc_chip *chip)
> -{
> -	struct cpu_thread *c;
> -
> -	prlog(PR_DEBUG, "SLW: Init chip 0x%x\n", chip->id);
> -	/* At power ON setup inits for fast-sleep */
> -	for_each_available_core_in_chip(c, chip->id) {
> -		idle_prepare_core(chip, c);
> -	}
> -}
> -
> -/* Workarounds while entering fast-sleep */
> -
> -static void fast_sleep_enter(void)
> -{
> -	uint32_t core = pir_to_core_id(this_cpu()->pir);
> -	uint32_t chip_id = this_cpu()->chip_id;
> -	struct cpu_thread *primary_thread;
> -	uint64_t tmp;
> -	int rc;
> -
> -	primary_thread = this_cpu()->primary;
> -
> -	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> -			&tmp);
> -	if (rc) {
> -		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(1):"
> -		      " rc=%d chip_id=%d core=%d\n",
> -		      rc, chip_id, core);
> -		return;
> -	}
> -
> -	primary_thread->save_l2_fir_action1 = tmp;
> -	primary_thread->in_fast_sleep = true;
> -
> -	tmp = tmp & ~0x0200000000000000ULL;
> -	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> -			 tmp);
> -	if (rc) {
> -		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(2):"
> -		      " rc=%d chip_id=%d core=%d\n",
> -		      rc, chip_id, core);
> -		return;
> -	}
> -	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> -			&tmp);
> -	if (rc) {
> -		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(3):"
> -		      " rc=%d chip_id=%d core=%d\n",
> -		      rc, chip_id, core);
> -		return;
> -	}
> -
> -}
> -
> -/* Workarounds while exiting fast-sleep */
> -
> -void fast_sleep_exit(void)
> -{
> -	uint32_t core = pir_to_core_id(this_cpu()->pir);
> -	uint32_t chip_id = this_cpu()->chip_id;
> -	struct cpu_thread *primary_thread;
> -	int rc;
> -
> -	primary_thread = this_cpu()->primary;
> -	primary_thread->in_fast_sleep = false;
> -
> -	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
> -			primary_thread->save_l2_fir_action1);
> -	if (rc) {
> -		prlog(PR_WARNING, "fast_sleep_exit XSCOM failed:"
> -		      " rc=%d chip_id=%d core=%d\n",
> -		      rc, chip_id, core);
> -		return;
> -	}
> -}
> -
> -/*
> - * Setup and cleanup method for fast-sleep workarounds
> - * state = 1 fast-sleep
> - * enter = 1 Enter state
> - * exit  = 0 Exit state
> - */
> -
> -static int64_t opal_config_cpu_idle_state(uint64_t state, uint64_t enter)
> -{
> -	/* Only fast-sleep for now */
> -	if (state != 1)
> -		return OPAL_PARAMETER;	
> -
> -	switch(enter) {
> -	case 1:
> -		fast_sleep_enter();
> -		break;
> -	case 0:
> -		fast_sleep_exit();
> -		break;
> -	default:
> -		return OPAL_PARAMETER;
> -	}
> -
> -	return OPAL_SUCCESS;
> -}
> -
> -opal_call(OPAL_CONFIG_CPU_IDLE_STATE, opal_config_cpu_idle_state, 2);
> -#endif
> -
>   int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val)
>   {
>   
> @@ -1330,28 +889,7 @@ int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val)
>   
>   #ifdef CONFIG_P8
>   	} else if (proc_gen == proc_gen_p8) {
> -		int spr_is_supported = 0;
> -		void *image;
> -		int i;
> -
> -		/* Check of the SPR is supported by libpore */
> -		for (i = 0; i < SLW_SPR_REGS_SIZE ; i++)  {
> -			if (sprn == SLW_SPR_REGS[i].value)  {
> -				spr_is_supported = 1;
> -				break;
> -			}
> -		}
> -		if (!spr_is_supported) {
> -			log_simple_error(&e_info(OPAL_RC_SLW_REG),
> -			"SLW: Trying to set unsupported spr for CPU %x\n",
> -				c->pir);
> -			return OPAL_UNSUPPORTED;
> -		}
> -		image = (void *)chip->slw_base;
> -		rc = p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
> -					      sprn, val,
> -					      cpu_get_core_index(c),
> -					      cpu_get_thread_index(c));
> +		rc = opal_slw_set_reg_p8(c, chip, sprn, val);
>   #endif
>   	} else {
>   		log_simple_error(&e_info(OPAL_RC_SLW_REG),
> @@ -1386,18 +924,11 @@ void slw_init(void)
>   		return;
>   	}
>   
> -	if (proc_gen == proc_gen_p8) {
>   #ifdef CONFIG_P8
> -		for_each_chip(chip) {
> -			slw_init_chip_p8(chip);
> -			if(slw_image_check_p8(chip))
> -				wakeup_engine_state = WAKEUP_ENGINE_PRESENT;
> -			if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT)
> -				slw_late_init_p8(chip);
> -		}
> -		p8_sbe_init_timer();
> +	if (proc_gen == proc_gen_p8)
> +		slw_p8_init();
>   #endif
> -	} else if (proc_gen == proc_gen_p9) {
> +	if (proc_gen == proc_gen_p9) {
>   		for_each_chip(chip) {
>   			slw_init_chip_p9(chip);
>   			if(slw_image_check_p9(chip))
> diff --git a/hw/xive.c b/hw/xive.c
> index 51b03549a..34b92f1e9 100644
> --- a/hw/xive.c
> +++ b/hw/xive.c
> @@ -7,6 +7,7 @@
>    */
>   
>   #include <skiboot.h>
> +#include <slw.h>
>   #include <xscom.h>
>   #include <chip.h>
>   #include <io.h>
> diff --git a/hw/xive2.c b/hw/xive2.c
> index 30293cdf1..ea55423bb 100644
> --- a/hw/xive2.c
> +++ b/hw/xive2.c
> @@ -9,6 +9,7 @@
>   #define pr_fmt(fmt) "XIVE: " fmt
>   
>   #include <skiboot.h>
> +#include <slw.h>
>   #include <xscom.h>
>   #include <chip.h>
>   #include <io.h>
> diff --git a/include/skiboot.h b/include/skiboot.h
> index e2a1b5fc6..db08f45f4 100644
> --- a/include/skiboot.h
> +++ b/include/skiboot.h
> @@ -216,7 +216,6 @@ extern void uart_init(void);
>   extern void mbox_init(void);
>   extern void early_uart_init(void);
>   extern void homer_init(void);
> -extern void slw_init(void);
>   extern void add_cpu_idle_state_properties(void);
>   extern void lpc_rtc_init(void);
>   
> @@ -303,19 +302,8 @@ extern int  prd_hbrt_fsp_msg_notify(void *data, u32 dsize);
>   /* Flatten device-tree */
>   extern void *create_dtb(const struct dt_node *root, bool exclusive);
>   
> -/* Track failure in Wakup engine */
> -enum wakeup_engine_states {
> -	WAKEUP_ENGINE_NOT_PRESENT,
> -	WAKEUP_ENGINE_PRESENT,
> -	WAKEUP_ENGINE_FAILED
> -};
> -extern enum wakeup_engine_states wakeup_engine_state;
> -extern bool has_deep_states;
>   extern void nx_p9_rng_late_init(void);
>   
> -/* Patch SPR in SLW image */
> -extern int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
> -
>   extern void fast_sleep_exit(void);
>   
>   /* Fallback fake RTC */
> diff --git a/include/slw.h b/include/slw.h
> new file mode 100644
> index 000000000..299cbf191
> --- /dev/null
> +++ b/include/slw.h
> @@ -0,0 +1,48 @@
> +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
> +
> +#ifndef __SLW_H
> +#define __SLW_H
> +
> +#include <stdint.h>
> +#include <stdbool.h>
> +
> +#include <ccan/short_types/short_types.h>
> +
> +/* Define device-tree fields */
> +#define MAX_NAME_LEN	16
> +struct cpu_idle_states {
> +	char name[MAX_NAME_LEN];
> +	u32 latency_ns;
> +	u32 residency_ns;
> +	/*
> +	 * Register value/mask used to select different idle states.
> +	 * PMICR in POWER8 and PSSCR in POWER9
> +	 */
> +	u64 pm_ctrl_reg_val;
> +	u64 pm_ctrl_reg_mask;
> +	u32 flags;
> +};
> +
> +/* Track failure in Wakup engine */
> +enum wakeup_engine_states {
> +	WAKEUP_ENGINE_NOT_PRESENT,
> +	WAKEUP_ENGINE_PRESENT,
> +	WAKEUP_ENGINE_FAILED
> +};
> +extern enum wakeup_engine_states wakeup_engine_state;
> +extern bool has_deep_states;
> +
> +/* Patch SPR in SLW image */
> +extern int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
> +
> +extern void slw_init(void);
> +
> +/* P8 specific */
> +struct cpu_thread;
> +struct proc_chip;
> +extern int64_t opal_slw_set_reg_p8(struct cpu_thread *c, struct proc_chip *chip,
> +			    uint64_t sprn, uint64_t val);
> +extern void slw_p8_init(void);
> +extern void find_cpu_idle_state_properties_p8(struct cpu_idle_states **states, int *nr_states, bool *can_sleep);
> +
> +#endif /* __SKIBOOT_H */
>
diff mbox series

Patch

diff --git a/core/fast-reboot.c b/core/fast-reboot.c
index 2696348af..fedfa88cc 100644
--- a/core/fast-reboot.c
+++ b/core/fast-reboot.c
@@ -6,6 +6,7 @@ 
  */
 
 #include <skiboot.h>
+#include <slw.h>
 #include <cpu.h>
 #include <console.h>
 #include <fsp.h>
diff --git a/core/init.c b/core/init.c
index c3e0c494d..deead5ecc 100644
--- a/core/init.c
+++ b/core/init.c
@@ -6,6 +6,7 @@ 
  */
 
 #include <skiboot.h>
+#include <slw.h>
 #include <psi.h>
 #include <chiptod.h>
 #include <nx.h>
diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index 8f509739d..7327cec35 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -10,7 +10,7 @@  HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o
 HW_OBJS += occ-sensor.o vas.o dio-p9.o lpc-port80h.o cache-p9.o
 HW_OBJS += npu-opal.o ocmb.o xive2.o pau.o pau-hw-procedures.o
 ifeq ($(CONFIG_P8),1)
-HW_OBJS += phb3.o sbe-p8.o
+HW_OBJS += phb3.o sbe-p8.o slw-p8.o
 endif
 HW=hw/built-in.a
 
diff --git a/hw/imc.c b/hw/imc.c
index cbd68edc4..97e0809f0 100644
--- a/hw/imc.c
+++ b/hw/imc.c
@@ -8,6 +8,7 @@ 
 
 #define pr_fmt(fmt)  "IMC: " fmt
 #include <skiboot.h>
+#include <slw.h>
 #include <xscom.h>
 #include <imc.h>
 #include <chip.h>
diff --git a/hw/nx.c b/hw/nx.c
index fdadf53c7..13c681b2c 100644
--- a/hw/nx.c
+++ b/hw/nx.c
@@ -6,6 +6,7 @@ 
  */
 
 #include <skiboot.h>
+#include <slw.h>
 #include <xscom.h>
 #include <io.h>
 #include <cpu.h>
diff --git a/hw/slw-p8.c b/hw/slw-p8.c
new file mode 100644
index 000000000..0a27a8fcc
--- /dev/null
+++ b/hw/slw-p8.c
@@ -0,0 +1,508 @@ 
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+#include <skiboot.h>
+#include <slw.h>
+#include <xscom.h>
+#include <xscom-p8-regs.h>
+#include <cpu.h>
+#include <chip.h>
+#include <interrupts.h>
+#include <timebase.h>
+#include <errorlog.h>
+#include <libfdt/libfdt.h>
+#include <opal-api.h>
+#include <sbe-p8.h>
+
+#include <p8_pore_table_gen_api.H>
+#include <sbe_xip_image.h>
+
+/*
+ * It would be nice to be able to define non-static log entry types and share
+ * these with slw.c
+ */
+DEFINE_LOG_ENTRY(OPAL_RC_SLW_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
+		 OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
+		 OPAL_NA);
+
+DEFINE_LOG_ENTRY(OPAL_RC_SLW_SET, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
+		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
+		 OPAL_NA);
+
+DEFINE_LOG_ENTRY(OPAL_RC_SLW_GET, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
+		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
+		 OPAL_NA);
+
+DEFINE_LOG_ENTRY(OPAL_RC_SLW_REG, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
+		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
+		 OPAL_NA);
+
+static bool slw_general_init(struct proc_chip *chip, struct cpu_thread *c)
+{
+	uint32_t core = pir_to_core_id(c->pir);
+	uint64_t tmp;
+	int rc;
+
+	/* PowerManagement GP0 clear PM_DISABLE */
+	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
+	if (rc) {
+		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
+				"SLW: Failed to read PM_GP0\n");
+		return false;
+	}
+	tmp = tmp & ~0x8000000000000000ULL;
+	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), tmp);
+	if (rc) {
+		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
+				"SLW: Failed to write PM_GP0\n");
+		return false;
+	}
+	prlog(PR_TRACE, "SLW: PMGP0 set to 0x%016llx\n", tmp);
+
+	/* Read back for debug */
+	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
+	if (rc)
+		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
+				 "SLW: Failed to re-read PM_GP0. Continuing...\n");
+
+	prlog(PR_TRACE, "SLW: PMGP0 read   0x%016llx\n", tmp);
+
+	return true;
+}
+
+static bool slw_set_overrides(struct proc_chip *chip, struct cpu_thread *c)
+{
+	uint32_t core = pir_to_core_id(c->pir);
+	int rc;
+
+	rc = xscom_write(chip->id,
+			 XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SPECIAL_WAKEUP_PHYP),
+			 0);
+	if (rc) {
+		log_simple_error(&e_info(OPAL_RC_SLW_SET),
+			"SLW: Failed to write PM_SPECIAL_WAKEUP_PHYP\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool slw_set_idle_mode(struct proc_chip *chip, struct cpu_thread *c)
+{
+	uint32_t core = pir_to_core_id(c->pir);
+	uint64_t tmp;
+	int rc;
+
+	/*
+	 * PM GP1 allows fast/deep mode to be selected independently for sleep
+	 * and winkle. Init PM GP1 so that sleep happens in fast mode and
+	 * winkle happens in deep mode.
+	 * Make use of the OR XSCOM for this since the OCC might be manipulating
+	 * the PM_GP1 register as well. Before doing this ensure that the bits
+	 * managing idle states are cleared so as to override any bits set at
+	 * init time.
+	 */
+
+	tmp = ~EX_PM_GP1_SLEEP_WINKLE_MASK;
+	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_CLEAR_GP1),
+			 tmp);
+	if (rc) {
+		log_simple_error(&e_info(OPAL_RC_SLW_SET),
+						"SLW: Failed to write PM_GP1\n");
+		return false;
+	}
+
+	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SET_GP1),
+			 EX_PM_SETUP_GP1_FAST_SLEEP_DEEP_WINKLE);
+	if (rc) {
+		log_simple_error(&e_info(OPAL_RC_SLW_SET),
+						"SLW: Failed to write PM_GP1\n");
+		return false;
+	}
+
+	/* Read back for debug */
+	xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP1), &tmp);
+	prlog(PR_TRACE, "SLW: PMGP1 read   0x%016llx\n", tmp);
+	return true;
+}
+
+static bool slw_get_idle_state_history(struct proc_chip *chip, struct cpu_thread *c)
+{
+	uint32_t core = pir_to_core_id(c->pir);
+	uint64_t tmp;
+	int rc;
+
+	/* Cleanup history */
+	rc = xscom_read(chip->id,
+		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
+		   &tmp);
+	if (rc) {
+		log_simple_error(&e_info(OPAL_RC_SLW_GET),
+			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
+		return false;
+	}
+
+	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old1)\n",
+	    chip->id, core, tmp);
+
+	rc = xscom_read(chip->id,
+		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
+		   &tmp);
+
+	if (rc) {
+		log_simple_error(&e_info(OPAL_RC_SLW_GET),
+			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
+		return false;
+	}
+
+	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old2)\n",
+	    chip->id, core, tmp);
+
+	return true;
+}
+
+static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c)
+{
+	prlog(PR_TRACE, "FASTSLEEP: Prepare core %x:%x\n",
+	    chip->id, pir_to_core_id(c->pir));
+
+	if(!slw_general_init(chip, c))
+		return false;
+	if(!slw_set_overrides(chip, c))
+		return false;
+	if(!slw_set_idle_mode(chip, c))
+		return false;
+	if(!slw_get_idle_state_history(chip, c))
+		return false;
+
+	return true;
+
+}
+
+static struct cpu_idle_states nap_only_cpu_idle_states[] = {
+	{ /* nap */
+		.name = "nap",
+		.latency_ns = 4000,
+		.residency_ns = 100000,
+		.flags = 0*OPAL_PM_DEC_STOP \
+		       | 0*OPAL_PM_TIMEBASE_STOP  \
+		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
+		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+		       | 1*OPAL_PM_NAP_ENABLED \
+		       | 0*OPAL_PM_SLEEP_ENABLED \
+		       | 0*OPAL_PM_WINKLE_ENABLED \
+		       | 0*OPAL_USE_PMICR,
+		.pm_ctrl_reg_val = 0,
+		.pm_ctrl_reg_mask = 0 },
+};
+
+static struct cpu_idle_states power8_cpu_idle_states[] = {
+	{ /* nap */
+		.name = "nap",
+		.latency_ns = 4000,
+		.residency_ns = 100000,
+		.flags = 0*OPAL_PM_DEC_STOP \
+		       | 0*OPAL_PM_TIMEBASE_STOP  \
+		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
+		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+		       | 1*OPAL_PM_NAP_ENABLED \
+		       | 0*OPAL_USE_PMICR,
+		.pm_ctrl_reg_val = 0,
+		.pm_ctrl_reg_mask = 0 },
+	{ /* fast sleep (with workaround) */
+		.name = "fastsleep_",
+		.latency_ns = 40000,
+		.residency_ns = 300000000,
+		.flags = 1*OPAL_PM_DEC_STOP \
+		       | 1*OPAL_PM_TIMEBASE_STOP  \
+		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
+		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
+		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
+		       | 1*OPAL_PM_SLEEP_ENABLED_ER1 \
+		       | 0*OPAL_USE_PMICR, /* Not enabled until deep
+						states are available */
+		.pm_ctrl_reg_val = OPAL_PM_FASTSLEEP_PMICR,
+		.pm_ctrl_reg_mask = OPAL_PM_SLEEP_PMICR_MASK },
+	{ /* Winkle */
+		.name = "winkle",
+		.latency_ns = 10000000,
+		.residency_ns = 1000000000, /* Educated guess (not measured).
+					     * Winkle is not currently used by 
+					     * linux cpuidle subsystem so we
+					     * don't have real world user.
+					     * However, this should be roughly
+					     * accurate for when linux does
+					     * use it. */
+		.flags = 1*OPAL_PM_DEC_STOP \
+		       | 1*OPAL_PM_TIMEBASE_STOP  \
+		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
+		       | 1*OPAL_PM_LOSE_HYP_CONTEXT \
+		       | 1*OPAL_PM_LOSE_FULL_CONTEXT \
+		       | 1*OPAL_PM_WINKLE_ENABLED \
+		       | 0*OPAL_USE_PMICR, /* Currently choosing deep vs
+						fast via EX_PM_GP1 reg */
+		.pm_ctrl_reg_val = 0,
+		.pm_ctrl_reg_mask = 0 },
+};
+
+void find_cpu_idle_state_properties_p8(struct cpu_idle_states **states,
+				       int *nr_states, bool *can_sleep)
+{
+	struct proc_chip *chip;
+
+	chip = next_chip(NULL);
+	assert(chip);
+
+	*can_sleep = true;
+
+	if (chip->type == PROC_CHIP_P8_MURANO ||
+	    chip->type == PROC_CHIP_P8_VENICE ||
+	    chip->type == PROC_CHIP_P8_NAPLES) {
+		const struct dt_property *p;
+
+		p = dt_find_property(dt_root, "ibm,enabled-idle-states");
+		if (p)
+			prlog(PR_NOTICE,
+			      "SLW: HB-provided idle states property found\n");
+		*states = power8_cpu_idle_states;
+		*nr_states = ARRAY_SIZE(power8_cpu_idle_states);
+
+		/* Check if hostboot say we can sleep */
+		if (!p || !dt_prop_find_string(p, "fast-sleep")) {
+			prlog(PR_WARNING, "SLW: Sleep not enabled by HB"
+			      " on this platform\n");
+			*can_sleep = false;
+		}
+
+		/* Clip to NAP only on Murano and Venice DD1.x */
+		if ((chip->type == PROC_CHIP_P8_MURANO ||
+		     chip->type == PROC_CHIP_P8_VENICE) &&
+		    chip->ec_level < 0x20) {
+			prlog(PR_NOTICE, "SLW: Sleep not enabled on P8 DD1.x\n");
+			*can_sleep = false;
+		}
+
+	} else {
+		*states = nap_only_cpu_idle_states;
+		*nr_states = ARRAY_SIZE(nap_only_cpu_idle_states);
+	}
+}
+
+static void slw_patch_regs(struct proc_chip *chip)
+{
+	struct cpu_thread *c;
+	void *image = (void *)chip->slw_base;
+	int rc;
+
+	for_each_available_cpu(c) {
+		if (c->chip_id != chip->id)
+			continue;
+
+		/* Clear HRMOR */
+		rc =  p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
+					       P8_SPR_HRMOR, 0,
+					       cpu_get_core_index(c),
+					       cpu_get_thread_index(c));
+		if (rc) {
+			log_simple_error(&e_info(OPAL_RC_SLW_REG),
+				"SLW: Failed to set HRMOR for CPU %x\n",
+				c->pir);
+		}
+
+		/* XXX Add HIDs etc... */
+	}
+}
+
+static bool  slw_image_check_p8(struct proc_chip *chip)
+{
+	int64_t rc;
+
+	prlog(PR_DEBUG, "SLW: slw_check chip 0x%x\n", chip->id);
+	if (!chip->slw_base) {
+		prerror("SLW: No image found !\n");
+		return false;
+	}
+
+	/* Check actual image size */
+	rc = sbe_xip_get_scalar((void *)chip->slw_base, "image_size",
+				&chip->slw_image_size);
+	if (rc != 0) {
+		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
+			"SLW: Error %lld reading SLW image size\n", rc);
+		/* XXX Panic ? */
+		chip->slw_base = 0;
+		chip->slw_bar_size = 0;
+		chip->slw_image_size = 0;
+		return false;
+	}
+	prlog(PR_DEBUG, "SLW: Image size from image: 0x%llx\n",
+	      chip->slw_image_size);
+
+	if (chip->slw_image_size > chip->slw_bar_size) {
+		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
+			"SLW: Built-in image size larger than BAR size !\n");
+		/* XXX Panic ? */
+		return false;
+	}
+	return true;
+
+}
+
+static void slw_late_init_p8(struct proc_chip *chip)
+{
+
+	prlog(PR_DEBUG, "SLW: late Init chip 0x%x\n", chip->id);
+
+	/* Patch SLW image */
+        slw_patch_regs(chip);
+
+}
+static void slw_init_chip_p8(struct proc_chip *chip)
+{
+	struct cpu_thread *c;
+
+	prlog(PR_DEBUG, "SLW: Init chip 0x%x\n", chip->id);
+	/* At power ON setup inits for fast-sleep */
+	for_each_available_core_in_chip(c, chip->id) {
+		idle_prepare_core(chip, c);
+	}
+}
+
+/* Workarounds while entering fast-sleep */
+
+static void fast_sleep_enter(void)
+{
+	uint32_t core = pir_to_core_id(this_cpu()->pir);
+	uint32_t chip_id = this_cpu()->chip_id;
+	struct cpu_thread *primary_thread;
+	uint64_t tmp;
+	int rc;
+
+	primary_thread = this_cpu()->primary;
+
+	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
+			&tmp);
+	if (rc) {
+		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(1):"
+		      " rc=%d chip_id=%d core=%d\n",
+		      rc, chip_id, core);
+		return;
+	}
+
+	primary_thread->save_l2_fir_action1 = tmp;
+	primary_thread->in_fast_sleep = true;
+
+	tmp = tmp & ~0x0200000000000000ULL;
+	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
+			 tmp);
+	if (rc) {
+		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(2):"
+		      " rc=%d chip_id=%d core=%d\n",
+		      rc, chip_id, core);
+		return;
+	}
+	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
+			&tmp);
+	if (rc) {
+		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(3):"
+		      " rc=%d chip_id=%d core=%d\n",
+		      rc, chip_id, core);
+		return;
+	}
+
+}
+
+/* Workarounds while exiting fast-sleep */
+
+void fast_sleep_exit(void)
+{
+	uint32_t core = pir_to_core_id(this_cpu()->pir);
+	uint32_t chip_id = this_cpu()->chip_id;
+	struct cpu_thread *primary_thread;
+	int rc;
+
+	primary_thread = this_cpu()->primary;
+	primary_thread->in_fast_sleep = false;
+
+	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
+			primary_thread->save_l2_fir_action1);
+	if (rc) {
+		prlog(PR_WARNING, "fast_sleep_exit XSCOM failed:"
+		      " rc=%d chip_id=%d core=%d\n",
+		      rc, chip_id, core);
+		return;
+	}
+}
+
+/*
+ * Setup and cleanup method for fast-sleep workarounds
+ * state = 1 fast-sleep
+ * enter = 1 Enter state
+ * exit  = 0 Exit state
+ */
+
+static int64_t opal_config_cpu_idle_state(uint64_t state, uint64_t enter)
+{
+	/* Only fast-sleep for now */
+	if (state != 1)
+		return OPAL_PARAMETER;	
+
+	switch(enter) {
+	case 1:
+		fast_sleep_enter();
+		break;
+	case 0:
+		fast_sleep_exit();
+		break;
+	default:
+		return OPAL_PARAMETER;
+	}
+
+	return OPAL_SUCCESS;
+}
+
+opal_call(OPAL_CONFIG_CPU_IDLE_STATE, opal_config_cpu_idle_state, 2);
+
+int64_t opal_slw_set_reg_p8(struct cpu_thread *c, struct proc_chip *chip,
+			    uint64_t sprn, uint64_t val)
+{
+	int spr_is_supported = 0;
+	void *image;
+	int i;
+	int rc;
+
+	/* Check of the SPR is supported by libpore */
+	for (i = 0; i < SLW_SPR_REGS_SIZE ; i++)  {
+		if (sprn == SLW_SPR_REGS[i].value)  {
+			spr_is_supported = 1;
+			break;
+		}
+	}
+	if (!spr_is_supported) {
+		log_simple_error(&e_info(OPAL_RC_SLW_REG),
+		"SLW: Trying to set unsupported spr for CPU %x\n",
+			c->pir);
+		return OPAL_UNSUPPORTED;
+	}
+	image = (void *)chip->slw_base;
+	rc = p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
+				      sprn, val,
+				      cpu_get_core_index(c),
+				      cpu_get_thread_index(c));
+	return rc;
+}
+
+void slw_p8_init(void)
+{
+	struct proc_chip *chip;
+
+	for_each_chip(chip) {
+		slw_init_chip_p8(chip);
+		if (slw_image_check_p8(chip))
+			wakeup_engine_state = WAKEUP_ENGINE_PRESENT;
+		if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT)
+			slw_late_init_p8(chip);
+	}
+	p8_sbe_init_timer();
+}
diff --git a/hw/slw.c b/hw/slw.c
index bc53960b7..6d7c8619c 100644
--- a/hw/slw.c
+++ b/hw/slw.c
@@ -7,8 +7,8 @@ 
  */
 
 #include <skiboot.h>
+#include <slw.h>
 #include <xscom.h>
-#include <xscom-p8-regs.h>
 #include <xscom-p9-regs.h>
 #include <xscom-p10-regs.h>
 #include <io.h>
@@ -22,12 +22,10 @@ 
 #include <libfdt/libfdt.h>
 #include <opal-api.h>
 #include <nvram.h>
-#include <sbe-p8.h>
 #include <xive.h>
 
 #include <p10_stop_api.H>
-#include <p8_pore_table_gen_api.H>
-#include <sbe_xip_image.h>
+//#include <sbe_xip_image.h>
 
 enum wakeup_engine_states wakeup_engine_state = WAKEUP_ENGINE_NOT_PRESENT;
 bool has_deep_states = false;
@@ -40,158 +38,6 @@  DEFINE_LOG_ENTRY(OPAL_RC_SLW_REG, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
 		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
 		 OPAL_NA);
 
-#ifdef CONFIG_P8
-DEFINE_LOG_ENTRY(OPAL_RC_SLW_INIT, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
-		 OPAL_PLATFORM_FIRMWARE, OPAL_PREDICTIVE_ERR_GENERAL,
-		 OPAL_NA);
-
-DEFINE_LOG_ENTRY(OPAL_RC_SLW_GET, OPAL_PLATFORM_ERR_EVT, OPAL_SLW,
-		 OPAL_PLATFORM_FIRMWARE, OPAL_INFO,
-		 OPAL_NA);
-
-static bool slw_general_init(struct proc_chip *chip, struct cpu_thread *c)
-{
-	uint32_t core = pir_to_core_id(c->pir);
-	uint64_t tmp;
-	int rc;
-
-	/* PowerManagement GP0 clear PM_DISABLE */
-	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
-	if (rc) {
-		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
-				"SLW: Failed to read PM_GP0\n");
-		return false;
-	}
-	tmp = tmp & ~0x8000000000000000ULL;
-	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), tmp);
-	if (rc) {
-		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
-				"SLW: Failed to write PM_GP0\n");
-		return false;
-	}
-	prlog(PR_TRACE, "SLW: PMGP0 set to 0x%016llx\n", tmp);
-
-	/* Read back for debug */
-	rc = xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP0), &tmp);
-	if (rc)
-		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
-				 "SLW: Failed to re-read PM_GP0. Continuing...\n");
-
-	prlog(PR_TRACE, "SLW: PMGP0 read   0x%016llx\n", tmp);
-
-	return true;
-}
-
-static bool slw_set_overrides(struct proc_chip *chip, struct cpu_thread *c)
-{
-	uint32_t core = pir_to_core_id(c->pir);
-	int rc;
-
-	rc = xscom_write(chip->id,
-			 XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SPECIAL_WAKEUP_PHYP),
-			 0);
-	if (rc) {
-		log_simple_error(&e_info(OPAL_RC_SLW_SET),
-			"SLW: Failed to write PM_SPECIAL_WAKEUP_PHYP\n");
-		return false;
-	}
-
-	return true;
-}
-
-static bool slw_set_idle_mode(struct proc_chip *chip, struct cpu_thread *c)
-{
-	uint32_t core = pir_to_core_id(c->pir);
-	uint64_t tmp;
-	int rc;
-
-	/*
-	 * PM GP1 allows fast/deep mode to be selected independently for sleep
-	 * and winkle. Init PM GP1 so that sleep happens in fast mode and
-	 * winkle happens in deep mode.
-	 * Make use of the OR XSCOM for this since the OCC might be manipulating
-	 * the PM_GP1 register as well. Before doing this ensure that the bits
-	 * managing idle states are cleared so as to override any bits set at
-	 * init time.
-	 */
-
-	tmp = ~EX_PM_GP1_SLEEP_WINKLE_MASK;
-	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_CLEAR_GP1),
-			 tmp);
-	if (rc) {
-		log_simple_error(&e_info(OPAL_RC_SLW_SET),
-						"SLW: Failed to write PM_GP1\n");
-		return false;
-	}
-
-	rc = xscom_write(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_SET_GP1),
-			 EX_PM_SETUP_GP1_FAST_SLEEP_DEEP_WINKLE);
-	if (rc) {
-		log_simple_error(&e_info(OPAL_RC_SLW_SET),
-						"SLW: Failed to write PM_GP1\n");
-		return false;
-	}
-
-	/* Read back for debug */
-	xscom_read(chip->id, XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_GP1), &tmp);
-	prlog(PR_TRACE, "SLW: PMGP1 read   0x%016llx\n", tmp);
-	return true;
-}
-
-static bool slw_get_idle_state_history(struct proc_chip *chip, struct cpu_thread *c)
-{
-	uint32_t core = pir_to_core_id(c->pir);
-	uint64_t tmp;
-	int rc;
-
-	/* Cleanup history */
-	rc = xscom_read(chip->id,
-		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
-		   &tmp);
-	if (rc) {
-		log_simple_error(&e_info(OPAL_RC_SLW_GET),
-			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
-		return false;
-	}
-
-	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old1)\n",
-	    chip->id, core, tmp);
-
-	rc = xscom_read(chip->id,
-		   XSCOM_ADDR_P8_EX_SLAVE(core, EX_PM_IDLE_STATE_HISTORY_PHYP),
-		   &tmp);
-
-	if (rc) {
-		log_simple_error(&e_info(OPAL_RC_SLW_GET),
-			"SLW: Failed to read PM_IDLE_STATE_HISTORY\n");
-		return false;
-	}
-
-	prlog(PR_TRACE, "SLW: core %x:%x history: 0x%016llx (old2)\n",
-	    chip->id, core, tmp);
-
-	return true;
-}
-
-static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c)
-{
-	prlog(PR_TRACE, "FASTSLEEP: Prepare core %x:%x\n",
-	    chip->id, pir_to_core_id(c->pir));
-
-	if(!slw_general_init(chip, c))
-		return false;
-	if(!slw_set_overrides(chip, c))
-		return false;
-	if(!slw_set_idle_mode(chip, c))
-		return false;
-	if(!slw_get_idle_state_history(chip, c))
-		return false;
-
-	return true;
-
-}
-#endif
-
 static bool slw_set_overrides_p10(struct proc_chip *chip, struct cpu_thread *c)
 {
 	uint64_t tmp;
@@ -245,89 +91,6 @@  static bool slw_set_overrides_p9(struct proc_chip *chip, struct cpu_thread *c)
 	return true;
 }
 
-/* Define device-tree fields */
-#define MAX_NAME_LEN	16
-struct cpu_idle_states {
-	char name[MAX_NAME_LEN];
-	u32 latency_ns;
-	u32 residency_ns;
-	/*
-	 * Register value/mask used to select different idle states.
-	 * PMICR in POWER8 and PSSCR in POWER9
-	 */
-	u64 pm_ctrl_reg_val;
-	u64 pm_ctrl_reg_mask;
-	u32 flags;
-};
-
-static struct cpu_idle_states nap_only_cpu_idle_states[] = {
-	{ /* nap */
-		.name = "nap",
-		.latency_ns = 4000,
-		.residency_ns = 100000,
-		.flags = 0*OPAL_PM_DEC_STOP \
-		       | 0*OPAL_PM_TIMEBASE_STOP  \
-		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
-		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
-		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
-		       | 1*OPAL_PM_NAP_ENABLED \
-		       | 0*OPAL_PM_SLEEP_ENABLED \
-		       | 0*OPAL_PM_WINKLE_ENABLED \
-		       | 0*OPAL_USE_PMICR,
-		.pm_ctrl_reg_val = 0,
-		.pm_ctrl_reg_mask = 0 },
-};
-
-static struct cpu_idle_states power8_cpu_idle_states[] = {
-	{ /* nap */
-		.name = "nap",
-		.latency_ns = 4000,
-		.residency_ns = 100000,
-		.flags = 0*OPAL_PM_DEC_STOP \
-		       | 0*OPAL_PM_TIMEBASE_STOP  \
-		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
-		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
-		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
-		       | 1*OPAL_PM_NAP_ENABLED \
-		       | 0*OPAL_USE_PMICR,
-		.pm_ctrl_reg_val = 0,
-		.pm_ctrl_reg_mask = 0 },
-	{ /* fast sleep (with workaround) */
-		.name = "fastsleep_",
-		.latency_ns = 40000,
-		.residency_ns = 300000000,
-		.flags = 1*OPAL_PM_DEC_STOP \
-		       | 1*OPAL_PM_TIMEBASE_STOP  \
-		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
-		       | 0*OPAL_PM_LOSE_HYP_CONTEXT \
-		       | 0*OPAL_PM_LOSE_FULL_CONTEXT \
-		       | 1*OPAL_PM_SLEEP_ENABLED_ER1 \
-		       | 0*OPAL_USE_PMICR, /* Not enabled until deep
-						states are available */
-		.pm_ctrl_reg_val = OPAL_PM_FASTSLEEP_PMICR,
-		.pm_ctrl_reg_mask = OPAL_PM_SLEEP_PMICR_MASK },
-	{ /* Winkle */
-		.name = "winkle",
-		.latency_ns = 10000000,
-		.residency_ns = 1000000000, /* Educated guess (not measured).
-					     * Winkle is not currently used by 
-					     * linux cpuidle subsystem so we
-					     * don't have real world user.
-					     * However, this should be roughly
-					     * accurate for when linux does
-					     * use it. */
-		.flags = 1*OPAL_PM_DEC_STOP \
-		       | 1*OPAL_PM_TIMEBASE_STOP  \
-		       | 1*OPAL_PM_LOSE_USER_CONTEXT \
-		       | 1*OPAL_PM_LOSE_HYP_CONTEXT \
-		       | 1*OPAL_PM_LOSE_FULL_CONTEXT \
-		       | 1*OPAL_PM_WINKLE_ENABLED \
-		       | 0*OPAL_USE_PMICR, /* Currently choosing deep vs
-						fast via EX_PM_GP1 reg */
-		.pm_ctrl_reg_val = 0,
-		.pm_ctrl_reg_mask = 0 },
-};
-
 /*
  * cpu_idle_states for key idle states of POWER9 that we want to
  * exploit.
@@ -796,9 +559,9 @@  static void slw_late_init_p10(struct proc_chip *chip)
 void add_cpu_idle_state_properties(void)
 {
 	struct dt_node *power_mgt;
-	struct cpu_idle_states *states;
+	struct cpu_idle_states *states = NULL;
 	struct proc_chip *chip;
-	int nr_states;
+	int nr_states = 0;
 
 	bool can_sleep = true;
 	bool has_stop_inst = false;
@@ -897,39 +660,12 @@  void add_cpu_idle_state_properties(void)
 			}
 			if (wakeup_engine_state != WAKEUP_ENGINE_PRESENT)
 				has_deep_states = false;
-	} else if (chip->type == PROC_CHIP_P8_MURANO ||
-	    chip->type == PROC_CHIP_P8_VENICE ||
-	    chip->type == PROC_CHIP_P8_NAPLES) {
-		const struct dt_property *p;
-
-		p = dt_find_property(dt_root, "ibm,enabled-idle-states");
-		if (p)
-			prlog(PR_NOTICE,
-			      "SLW: HB-provided idle states property found\n");
-		states = power8_cpu_idle_states;
-		nr_states = ARRAY_SIZE(power8_cpu_idle_states);
-
-		/* Check if hostboot say we can sleep */
-		if (!p || !dt_prop_find_string(p, "fast-sleep")) {
-			prlog(PR_WARNING, "SLW: Sleep not enabled by HB"
-			      " on this platform\n");
-			can_sleep = false;
-		}
-
-		/* Clip to NAP only on Murano and Venice DD1.x */
-		if ((chip->type == PROC_CHIP_P8_MURANO ||
-		     chip->type == PROC_CHIP_P8_VENICE) &&
-		    chip->ec_level < 0x20) {
-			prlog(PR_NOTICE, "SLW: Sleep not enabled on P8 DD1.x\n");
-			can_sleep = false;
-		}
-
+#ifdef CONFIG_P8
 	} else {
-		states = nap_only_cpu_idle_states;
-		nr_states = ARRAY_SIZE(nap_only_cpu_idle_states);
+		find_cpu_idle_state_properties_p8(&states, &nr_states, &can_sleep);
+#endif
 	}
 
-
 	/*
 	 * Currently we can't append strings and cells to dt properties.
 	 * So create buffers to which you can append values, then create
@@ -1112,183 +848,6 @@  static bool  slw_image_check_p9(struct proc_chip *chip)
 
 }
 
-#ifdef CONFIG_P8
-static void slw_patch_regs(struct proc_chip *chip)
-{
-	struct cpu_thread *c;
-	void *image = (void *)chip->slw_base;
-	int rc;
-
-	for_each_available_cpu(c) {
-		if (c->chip_id != chip->id)
-			continue;
-
-		/* Clear HRMOR */
-		rc =  p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
-					       P8_SPR_HRMOR, 0,
-					       cpu_get_core_index(c),
-					       cpu_get_thread_index(c));
-		if (rc) {
-			log_simple_error(&e_info(OPAL_RC_SLW_REG),
-				"SLW: Failed to set HRMOR for CPU %x\n",
-				c->pir);
-		}
-
-		/* XXX Add HIDs etc... */
-	}
-}
-
-static bool  slw_image_check_p8(struct proc_chip *chip)
-{
-	int64_t rc;
-
-	prlog(PR_DEBUG, "SLW: slw_check chip 0x%x\n", chip->id);
-	if (!chip->slw_base) {
-		prerror("SLW: No image found !\n");
-		return false;
-	}
-
-	/* Check actual image size */
-	rc = sbe_xip_get_scalar((void *)chip->slw_base, "image_size",
-				&chip->slw_image_size);
-	if (rc != 0) {
-		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
-			"SLW: Error %lld reading SLW image size\n", rc);
-		/* XXX Panic ? */
-		chip->slw_base = 0;
-		chip->slw_bar_size = 0;
-		chip->slw_image_size = 0;
-		return false;
-	}
-	prlog(PR_DEBUG, "SLW: Image size from image: 0x%llx\n",
-	      chip->slw_image_size);
-
-	if (chip->slw_image_size > chip->slw_bar_size) {
-		log_simple_error(&e_info(OPAL_RC_SLW_INIT),
-			"SLW: Built-in image size larger than BAR size !\n");
-		/* XXX Panic ? */
-		return false;
-	}
-	return true;
-
-}
-
-static void slw_late_init_p8(struct proc_chip *chip)
-{
-
-	prlog(PR_DEBUG, "SLW: late Init chip 0x%x\n", chip->id);
-
-	/* Patch SLW image */
-        slw_patch_regs(chip);
-
-}
-static void slw_init_chip_p8(struct proc_chip *chip)
-{
-	struct cpu_thread *c;
-
-	prlog(PR_DEBUG, "SLW: Init chip 0x%x\n", chip->id);
-	/* At power ON setup inits for fast-sleep */
-	for_each_available_core_in_chip(c, chip->id) {
-		idle_prepare_core(chip, c);
-	}
-}
-
-/* Workarounds while entering fast-sleep */
-
-static void fast_sleep_enter(void)
-{
-	uint32_t core = pir_to_core_id(this_cpu()->pir);
-	uint32_t chip_id = this_cpu()->chip_id;
-	struct cpu_thread *primary_thread;
-	uint64_t tmp;
-	int rc;
-
-	primary_thread = this_cpu()->primary;
-
-	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
-			&tmp);
-	if (rc) {
-		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(1):"
-		      " rc=%d chip_id=%d core=%d\n",
-		      rc, chip_id, core);
-		return;
-	}
-
-	primary_thread->save_l2_fir_action1 = tmp;
-	primary_thread->in_fast_sleep = true;
-
-	tmp = tmp & ~0x0200000000000000ULL;
-	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
-			 tmp);
-	if (rc) {
-		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(2):"
-		      " rc=%d chip_id=%d core=%d\n",
-		      rc, chip_id, core);
-		return;
-	}
-	rc = xscom_read(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
-			&tmp);
-	if (rc) {
-		prlog(PR_WARNING, "fast_sleep_enter XSCOM failed(3):"
-		      " rc=%d chip_id=%d core=%d\n",
-		      rc, chip_id, core);
-		return;
-	}
-
-}
-
-/* Workarounds while exiting fast-sleep */
-
-void fast_sleep_exit(void)
-{
-	uint32_t core = pir_to_core_id(this_cpu()->pir);
-	uint32_t chip_id = this_cpu()->chip_id;
-	struct cpu_thread *primary_thread;
-	int rc;
-
-	primary_thread = this_cpu()->primary;
-	primary_thread->in_fast_sleep = false;
-
-	rc = xscom_write(chip_id, XSCOM_ADDR_P8_EX(core, L2_FIR_ACTION1),
-			primary_thread->save_l2_fir_action1);
-	if (rc) {
-		prlog(PR_WARNING, "fast_sleep_exit XSCOM failed:"
-		      " rc=%d chip_id=%d core=%d\n",
-		      rc, chip_id, core);
-		return;
-	}
-}
-
-/*
- * Setup and cleanup method for fast-sleep workarounds
- * state = 1 fast-sleep
- * enter = 1 Enter state
- * exit  = 0 Exit state
- */
-
-static int64_t opal_config_cpu_idle_state(uint64_t state, uint64_t enter)
-{
-	/* Only fast-sleep for now */
-	if (state != 1)
-		return OPAL_PARAMETER;	
-
-	switch(enter) {
-	case 1:
-		fast_sleep_enter();
-		break;
-	case 0:
-		fast_sleep_exit();
-		break;
-	default:
-		return OPAL_PARAMETER;
-	}
-
-	return OPAL_SUCCESS;
-}
-
-opal_call(OPAL_CONFIG_CPU_IDLE_STATE, opal_config_cpu_idle_state, 2);
-#endif
-
 int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val)
 {
 
@@ -1330,28 +889,7 @@  int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val)
 
 #ifdef CONFIG_P8
 	} else if (proc_gen == proc_gen_p8) {
-		int spr_is_supported = 0;
-		void *image;
-		int i;
-
-		/* Check of the SPR is supported by libpore */
-		for (i = 0; i < SLW_SPR_REGS_SIZE ; i++)  {
-			if (sprn == SLW_SPR_REGS[i].value)  {
-				spr_is_supported = 1;
-				break;
-			}
-		}
-		if (!spr_is_supported) {
-			log_simple_error(&e_info(OPAL_RC_SLW_REG),
-			"SLW: Trying to set unsupported spr for CPU %x\n",
-				c->pir);
-			return OPAL_UNSUPPORTED;
-		}
-		image = (void *)chip->slw_base;
-		rc = p8_pore_gen_cpureg_fixed(image, P8_SLW_MODEBUILD_SRAM,
-					      sprn, val,
-					      cpu_get_core_index(c),
-					      cpu_get_thread_index(c));
+		rc = opal_slw_set_reg_p8(c, chip, sprn, val);
 #endif
 	} else {
 		log_simple_error(&e_info(OPAL_RC_SLW_REG),
@@ -1386,18 +924,11 @@  void slw_init(void)
 		return;
 	}
 
-	if (proc_gen == proc_gen_p8) {
 #ifdef CONFIG_P8
-		for_each_chip(chip) {
-			slw_init_chip_p8(chip);
-			if(slw_image_check_p8(chip))
-				wakeup_engine_state = WAKEUP_ENGINE_PRESENT;
-			if (wakeup_engine_state == WAKEUP_ENGINE_PRESENT)
-				slw_late_init_p8(chip);
-		}
-		p8_sbe_init_timer();
+	if (proc_gen == proc_gen_p8)
+		slw_p8_init();
 #endif
-	} else if (proc_gen == proc_gen_p9) {
+	if (proc_gen == proc_gen_p9) {
 		for_each_chip(chip) {
 			slw_init_chip_p9(chip);
 			if(slw_image_check_p9(chip))
diff --git a/hw/xive.c b/hw/xive.c
index 51b03549a..34b92f1e9 100644
--- a/hw/xive.c
+++ b/hw/xive.c
@@ -7,6 +7,7 @@ 
  */
 
 #include <skiboot.h>
+#include <slw.h>
 #include <xscom.h>
 #include <chip.h>
 #include <io.h>
diff --git a/hw/xive2.c b/hw/xive2.c
index 30293cdf1..ea55423bb 100644
--- a/hw/xive2.c
+++ b/hw/xive2.c
@@ -9,6 +9,7 @@ 
 #define pr_fmt(fmt) "XIVE: " fmt
 
 #include <skiboot.h>
+#include <slw.h>
 #include <xscom.h>
 #include <chip.h>
 #include <io.h>
diff --git a/include/skiboot.h b/include/skiboot.h
index e2a1b5fc6..db08f45f4 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -216,7 +216,6 @@  extern void uart_init(void);
 extern void mbox_init(void);
 extern void early_uart_init(void);
 extern void homer_init(void);
-extern void slw_init(void);
 extern void add_cpu_idle_state_properties(void);
 extern void lpc_rtc_init(void);
 
@@ -303,19 +302,8 @@  extern int  prd_hbrt_fsp_msg_notify(void *data, u32 dsize);
 /* Flatten device-tree */
 extern void *create_dtb(const struct dt_node *root, bool exclusive);
 
-/* Track failure in Wakup engine */
-enum wakeup_engine_states {
-	WAKEUP_ENGINE_NOT_PRESENT,
-	WAKEUP_ENGINE_PRESENT,
-	WAKEUP_ENGINE_FAILED
-};
-extern enum wakeup_engine_states wakeup_engine_state;
-extern bool has_deep_states;
 extern void nx_p9_rng_late_init(void);
 
-/* Patch SPR in SLW image */
-extern int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
-
 extern void fast_sleep_exit(void);
 
 /* Fallback fake RTC */
diff --git a/include/slw.h b/include/slw.h
new file mode 100644
index 000000000..299cbf191
--- /dev/null
+++ b/include/slw.h
@@ -0,0 +1,48 @@ 
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+#ifndef __SLW_H
+#define __SLW_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <ccan/short_types/short_types.h>
+
+/* Define device-tree fields */
+#define MAX_NAME_LEN	16
+struct cpu_idle_states {
+	char name[MAX_NAME_LEN];
+	u32 latency_ns;
+	u32 residency_ns;
+	/*
+	 * Register value/mask used to select different idle states.
+	 * PMICR in POWER8 and PSSCR in POWER9
+	 */
+	u64 pm_ctrl_reg_val;
+	u64 pm_ctrl_reg_mask;
+	u32 flags;
+};
+
+/* Track failure in Wakup engine */
+enum wakeup_engine_states {
+	WAKEUP_ENGINE_NOT_PRESENT,
+	WAKEUP_ENGINE_PRESENT,
+	WAKEUP_ENGINE_FAILED
+};
+extern enum wakeup_engine_states wakeup_engine_state;
+extern bool has_deep_states;
+
+/* Patch SPR in SLW image */
+extern int64_t opal_slw_set_reg(uint64_t cpu_pir, uint64_t sprn, uint64_t val);
+
+extern void slw_init(void);
+
+/* P8 specific */
+struct cpu_thread;
+struct proc_chip;
+extern int64_t opal_slw_set_reg_p8(struct cpu_thread *c, struct proc_chip *chip,
+			    uint64_t sprn, uint64_t val);
+extern void slw_p8_init(void);
+extern void find_cpu_idle_state_properties_p8(struct cpu_idle_states **states, int *nr_states, bool *can_sleep);
+
+#endif /* __SKIBOOT_H */