opal-prd: Add support for runtime OCC reset in ZZ

Message ID 1504168018-30755-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com
State New
Headers show
Series
  • opal-prd: Add support for runtime OCC reset in ZZ
Related show

Commit Message

Shilpasri G Bhat Aug. 31, 2017, 8:26 a.m.
This patch handles OCC_RESET runtime events in host opal-prd and also
provides support for calling 'hostinterface->wakeup()' which is
required for doing the reset operation.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
---
- This is based on top of
  https://lists.ozlabs.org/pipermail/skiboot/2017-August/008585.html
  which handles special wakeup in P9.

 core/hostservices.c          | 28 +++++++++++++++--------
 external/opal-prd/opal-prd.c | 51 +++++++++++++++++++++++++++++++++++++++++-
 external/opal-prd/thunk.S    |  2 +-
 hw/occ.c                     | 53 +++++++++++++++++++++++++++++++++++++++++++-
 hw/prd.c                     |  8 +++++++
 include/opal-api.h           | 10 +++++++++
 include/skiboot.h            |  2 ++
 7 files changed, 142 insertions(+), 12 deletions(-)

Comments

Mahesh Jagannath Salgaonkar Sept. 1, 2017, 7:12 a.m. | #1
On 08/31/2017 01:56 PM, Shilpasri G Bhat wrote:
> This patch handles OCC_RESET runtime events in host opal-prd and also
> provides support for calling 'hostinterface->wakeup()' which is
> required for doing the reset operation.
> 
> Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>

Patch looks good to me.

Reviewed-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

Thanks,
-Mahesh.

> ---
> - This is based on top of
>   https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.ozlabs.org_pipermail_skiboot_2017-2DAugust_008585.html&d=DwIGaQ&c=jf_iaSHvJObTbx-siA1ZOg&r=Ai3L2JW-0UCviNlQjlx57cFb6BIPotR3Af4uhUMAl18&m=jdbkUAOfWaC23BaUscD1vtdb8M8P3i8ldTb2DFHAsv8&s=J0KYU3rfdqVey-5Gt6HogvWcW2b9MQWtby4yGhOGkAo&e= 
>   which handles special wakeup in P9.
> 
>  core/hostservices.c          | 28 +++++++++++++++--------
>  external/opal-prd/opal-prd.c | 51 +++++++++++++++++++++++++++++++++++++++++-
>  external/opal-prd/thunk.S    |  2 +-
>  hw/occ.c                     | 53 +++++++++++++++++++++++++++++++++++++++++++-
>  hw/prd.c                     |  8 +++++++
>  include/opal-api.h           | 10 +++++++++
>  include/skiboot.h            |  2 ++
>  7 files changed, 142 insertions(+), 12 deletions(-)
> 
> diff --git a/core/hostservices.c b/core/hostservices.c
> index 345c8c0..799b483 100644
> --- a/core/hostservices.c
> +++ b/core/hostservices.c
> @@ -721,17 +721,23 @@ static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
>  	struct cpu_thread *cpu;
>  	int rc = OPAL_SUCCESS;
>  
> -	/*
> -	 * Mask out the top nibble of i_core since it may contain
> -	 * 0x4 (which we use for XSCOM targeting)
> -	 */
> -	i_core &= 0x0fffffff;
> +	switch (proc_gen) {
> +	case proc_gen_p8:
> +		i_core &= SPR_PIR_P8_MASK;
> +		i_core <<= 3;
> +		break;
> +	case proc_gen_p9:
> +		i_core &= SPR_PIR_P9_MASK;
> +		i_core <<= 2;
> +		break;
> +	default:
> +		return OPAL_UNSUPPORTED;
> +	}
>  
>  	/* What do we need to do ? */
>  	switch(i_mode) {
>  	case 0: /* Assert special wakeup */
> -		/* XXX Assume P8 */
> -		cpu = find_cpu_by_pir(i_core << 3);
> +		cpu = find_cpu_by_pir(i_core);
>  		if (!cpu)
>  			return OPAL_PARAMETER;
>  		prlog(PR_DEBUG, "HBRT: Special wakeup assert for core 0x%x,"
> @@ -742,8 +748,7 @@ static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
>  			cpu->hbrt_spec_wakeup++;
>  		return rc;
>  	case 1: /* Deassert special wakeup */
> -		/* XXX Assume P8 */
> -		cpu = find_cpu_by_pir(i_core << 3);
> +		cpu = find_cpu_by_pir(i_core);
>  		if (!cpu)
>  			return OPAL_PARAMETER;
>  		prlog(PR_DEBUG, "HBRT: Special wakeup release for core"
> @@ -774,6 +779,11 @@ static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
>  	}
>  }
>  
> +int core_special_wakeup(u32 core, u32 mode)
> +{
> +	return hservice_wakeup(core, mode);
> +}
> +
>  static struct host_interfaces hinterface = {
>  	.interface_version = HOSTBOOT_RUNTIME_INTERFACE_VERSION,
>  	.puts = hservice_puts,
> diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
> index a09a636..614b4b1 100644
> --- a/external/opal-prd/opal-prd.c
> +++ b/external/opal-prd/opal-prd.c
> @@ -506,6 +506,25 @@ int hservice_i2c_write(uint64_t i_master, uint16_t i_devAddr,
>  			 i_offset, i_length, i_data);
>  }
>  
> +int hservice_wakeup(u32 core, u32 mode)
> +{
> +	int rc;
> +	struct opal_prd_msg msg;
> +
> +	msg.hdr.type = OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP;
> +	msg.hdr.size = htobe16(sizeof(msg));
> +	msg.spl_wakeup.core = htobe32(core);
> +	msg.spl_wakeup.mode = htobe32(mode);
> +
> +	rc = write(ctx->fd, &msg, sizeof(msg));
> +	if (rc != sizeof(msg)) {
> +		pr_log(LOG_ERR, "FW:  failed for core %x : %m\n", core);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
>  static void ipmi_init(struct opal_prd_ctx *ctx)
>  {
>  	insert_module("ipmi_devintf");
> @@ -1353,9 +1372,24 @@ static int pm_complex_reset(uint64_t chip)
>  	return rc;
>  }
>  
> +static bool is_fsp(void)
> +{
> +	char *path;
> +	int rc;
> +
> +	rc = asprintf(&path, "%s/fsps", devicetree_base);
> +	if (rc < 0) {
> +		pr_log(LOG_ERR, "PRD: error creating '/fsps' path %m");
> +		return false;
> +	}
> +
> +	return access(path, F_OK) ? false : true;
> +}
> +
>  static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
>  		struct opal_prd_msg *msg)
>  {
> +	struct opal_prd_msg omsg;
>  	uint32_t proc;
>  	int rc;
>  
> @@ -1365,7 +1399,22 @@ static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
>  
>  	rc = pm_complex_reset(proc);
>  
> -	return rc;
> +	if (!is_fsp())
> +		return rc;
> +
> +	/* Send only for zz */
> +	omsg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS;
> +	omsg.hdr.size = htobe16(sizeof(omsg));
> +	omsg.occ_reset_status.chip = htobe64(proc);
> +	omsg.occ_reset_status.status = htobe64(rc);
> +
> +	rc = write(ctx->fd, &omsg, sizeof(omsg));
> +	if (rc != sizeof(omsg)) {
> +		pr_log(LOG_ERR, "FW: Failed to send OCC_RESET status message: %m");
> +		return rc;
> +	}
> +
> +	return 0;
>  }
>  
>  static int handle_msg_firmware_notify(struct opal_prd_ctx *ctx,
> diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
> index cca5890..ee3d7c3 100644
> --- a/external/opal-prd/thunk.S
> +++ b/external/opal-prd/thunk.S
> @@ -183,7 +183,7 @@ hinterface:
>  	DISABLED_THUNK(hservice_lid_load)
>  	DISABLED_THUNK(hservice_lid_unload)
>  	CALLBACK_THUNK(hservice_get_reserved_mem)
> -	DISABLED_THUNK(hservice_wakeup)
> +	CALLBACK_THUNK(hservice_wakeup)
>  	CALLBACK_THUNK(hservice_nanosleep)
>  	DISABLED_THUNK(hservice_report_occ_failure)
>  	CALLBACK_THUNK(hservice_clock_gettime)
> diff --git a/hw/occ.c b/hw/occ.c
> index 78c6a6a..a53ac92 100644
> --- a/hw/occ.c
> +++ b/hw/occ.c
> @@ -1837,6 +1837,46 @@ out:
>  	return rc;
>  }
>  
> +u32 last_seq_id;
> +
> +int fsp_occ_reset_status(u64 chipid, s64 status)
> +{
> +	struct fsp_msg *stat;
> +	int rc = OPAL_NO_MEM;
> +
> +	if (status == 0) {
> +		stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2, 0, last_seq_id);
> +		if (!stat)
> +			return rc;
> +
> +		rc = fsp_queue_msg(stat, fsp_freemsg);
> +		if (rc) {
> +			fsp_freemsg(stat);
> +			log_simple_error(&e_info(OPAL_RC_OCC_RESET),
> +				"OCC: Error %d queueing FSP OCC RESET STATUS message\n",
> +				rc);
> +		}
> +	} else {
> +		struct proc_chip *chip = get_chip(chipid);
> +
> +		if (!chip)
> +			return OPAL_PARAMETER;
> +
> +		stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2,
> +				 0xfe00 | (chip->pcid & 0xff), last_seq_id);
> +		if (!stat)
> +			return rc;
> +		rc = fsp_queue_msg(stat, fsp_freemsg);
> +		if (rc) {
> +			fsp_freemsg(stat);
> +			log_simple_error(&e_info(OPAL_RC_OCC_RESET),
> +			  "OCC: Error %d queueing FSP OCC RESET STATUS message\n",
> +				rc);
> +		}
> +	}
> +	return rc;
> +}
> +
>  static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
>  {
>  	struct fsp_msg *rsp, *stat;
> @@ -1877,7 +1917,18 @@ static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
>  	 * FSP will request OCC to left in stopped state.
>  	 */
>  
> -	rc = host_services_occ_stop();
> +	switch (proc_gen) {
> +	case proc_gen_p8:
> +		rc = host_services_occ_stop();
> +		break;
> +	case proc_gen_p9:
> +		last_seq_id = seq_id;
> +		for_each_chip(chip)
> +			prd_occ_reset(chip->id);
> +		return;
> +	default:
> +		return;
> +	}
>  
>  	/* Handle fallback to preload */
>  	if (rc == -ENOENT && chip->homer_base) {
> diff --git a/hw/prd.c b/hw/prd.c
> index d076c19..dcda9c8 100644
> --- a/hw/prd.c
> +++ b/hw/prd.c
> @@ -418,6 +418,14 @@ static int64_t opal_prd_msg(struct opal_prd_msg *msg)
>  	case OPAL_PRD_MSG_TYPE_FIRMWARE_REQUEST:
>  		rc = prd_msg_handle_firmware_req(msg);
>  		break;
> +	case OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS:
> +		rc = fsp_occ_reset_status(msg->occ_reset_status.chip,
> +					  msg->occ_reset_status.status);
> +		break;
> +	case OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP:
> +		rc = core_special_wakeup(msg->spl_wakeup.core,
> +					 msg->spl_wakeup.mode);
> +		break;
>  	default:
>  		rc = OPAL_UNSUPPORTED;
>  	}
> diff --git a/include/opal-api.h b/include/opal-api.h
> index 0ff0db0..2f303f9 100644
> --- a/include/opal-api.h
> +++ b/include/opal-api.h
> @@ -1052,6 +1052,8 @@ enum opal_prd_msg_type {
>  	OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE, /* HBRT <-- OPAL */
>  	OPAL_PRD_MSG_TYPE_FIRMWARE_NOTIFY, /* HBRT <-- OPAL */
>  	OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH, /* HBRT <-- OPAL */
> +	OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS, /* HBRT --> OPAL */
> +	OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP, /* HBRT --> OPAL */
>  };
>  
>  struct opal_prd_msg_header {
> @@ -1099,6 +1101,14 @@ struct opal_prd_msg {
>  		struct {
>  			__be64	chip;
>  		} sbe_passthrough;
> +		struct {
> +			__be64 chip;
> +			__be64 status; /* 0 SUCCESS */
> +		} occ_reset_status;
> +		struct {
> +			__be32 core;
> +			__be32 mode;
> +		} spl_wakeup;
>  	};
>  };
>  
> diff --git a/include/skiboot.h b/include/skiboot.h
> index 4b7d519..5eb9188 100644
> --- a/include/skiboot.h
> +++ b/include/skiboot.h
> @@ -317,4 +317,6 @@ extern int occ_sensor_group_clear(u32 group_hndl, int token);
>  extern void occ_add_sensor_groups(struct dt_node *sg, u32  *phandles,
>  				  int nr_phandles, int chipid);
>  
> +extern int fsp_occ_reset_status(u64 chipid, s64 status);
> +extern int core_special_wakeup(u32 core, u32 mode);
>  #endif /* __SKIBOOT_H */
>
Vasant Hegde Sept. 4, 2017, 2:32 p.m. | #2
On 08/31/2017 01:56 PM, Shilpasri G Bhat wrote:
> This patch handles OCC_RESET runtime events in host opal-prd and also
> provides support for calling 'hostinterface->wakeup()' which is
> required for doing the reset operation.
>
> Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
> ---
> - This is based on top of
>   https://lists.ozlabs.org/pipermail/skiboot/2017-August/008585.html
>   which handles special wakeup in P9.
>
>  core/hostservices.c          | 28 +++++++++++++++--------
>  external/opal-prd/opal-prd.c | 51 +++++++++++++++++++++++++++++++++++++++++-
>  external/opal-prd/thunk.S    |  2 +-
>  hw/occ.c                     | 53 +++++++++++++++++++++++++++++++++++++++++++-
>  hw/prd.c                     |  8 +++++++
>  include/opal-api.h           | 10 +++++++++
>  include/skiboot.h            |  2 ++
>  7 files changed, 142 insertions(+), 12 deletions(-)
>

.../...

> diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
> index cca5890..ee3d7c3 100644
> --- a/external/opal-prd/thunk.S
> +++ b/external/opal-prd/thunk.S
> @@ -183,7 +183,7 @@ hinterface:
>  	DISABLED_THUNK(hservice_lid_load)
>  	DISABLED_THUNK(hservice_lid_unload)
>  	CALLBACK_THUNK(hservice_get_reserved_mem)
> -	DISABLED_THUNK(hservice_wakeup)
> +	CALLBACK_THUNK(hservice_wakeup)

And you should detect service processor type and disable wakeup interface on BMC 
system.
(similar to pnor_read call. See run_prd_daemon()).

> diff --git a/hw/occ.c b/hw/occ.c
> index 78c6a6a..a53ac92 100644
> --- a/hw/occ.c
> +++ b/hw/occ.c
> @@ -1837,6 +1837,46 @@ out:
>  	return rc;
>  }
>
> +u32 last_seq_id;
> +
> +int fsp_occ_reset_status(u64 chipid, s64 status)
> +{
> +	struct fsp_msg *stat;
> +	int rc = OPAL_NO_MEM;
> +
> +	if (status == 0) {

How about something like below :
	if (status == 0)
		ret = 0;
	else
		ret = 0xfe00 | (chip->pcid & 0xff);

And then just call fsp_mkmsg. That way you can avoid duplicate code.

-Vasant

> +		stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2, 0, last_seq_id);
> +		if (!stat)
> +			return rc;
> +
> +		rc = fsp_queue_msg(stat, fsp_freemsg);
> +		if (rc) {
> +			fsp_freemsg(stat);
> +			log_simple_error(&e_info(OPAL_RC_OCC_RESET),
> +				"OCC: Error %d queueing FSP OCC RESET STATUS message\n",
> +				rc);
> +		}
> +	} else {
> +		struct proc_chip *chip = get_chip(chipid);
> +
> +		if (!chip)
> +			return OPAL_PARAMETER;
> +
> +		stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2,
> +				 0xfe00 | (chip->pcid & 0xff), last_seq_id);
> +		if (!stat)
> +			return rc;
> +		rc = fsp_queue_msg(stat, fsp_freemsg);
> +		if (rc) {
> +			fsp_freemsg(stat);
> +			log_simple_error(&e_info(OPAL_RC_OCC_RESET),
> +			  "OCC: Error %d queueing FSP OCC RESET STATUS message\n",
> +				rc);
> +		}
> +	}
> +	return rc;
> +}

Patch

diff --git a/core/hostservices.c b/core/hostservices.c
index 345c8c0..799b483 100644
--- a/core/hostservices.c
+++ b/core/hostservices.c
@@ -721,17 +721,23 @@  static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
 	struct cpu_thread *cpu;
 	int rc = OPAL_SUCCESS;
 
-	/*
-	 * Mask out the top nibble of i_core since it may contain
-	 * 0x4 (which we use for XSCOM targeting)
-	 */
-	i_core &= 0x0fffffff;
+	switch (proc_gen) {
+	case proc_gen_p8:
+		i_core &= SPR_PIR_P8_MASK;
+		i_core <<= 3;
+		break;
+	case proc_gen_p9:
+		i_core &= SPR_PIR_P9_MASK;
+		i_core <<= 2;
+		break;
+	default:
+		return OPAL_UNSUPPORTED;
+	}
 
 	/* What do we need to do ? */
 	switch(i_mode) {
 	case 0: /* Assert special wakeup */
-		/* XXX Assume P8 */
-		cpu = find_cpu_by_pir(i_core << 3);
+		cpu = find_cpu_by_pir(i_core);
 		if (!cpu)
 			return OPAL_PARAMETER;
 		prlog(PR_DEBUG, "HBRT: Special wakeup assert for core 0x%x,"
@@ -742,8 +748,7 @@  static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
 			cpu->hbrt_spec_wakeup++;
 		return rc;
 	case 1: /* Deassert special wakeup */
-		/* XXX Assume P8 */
-		cpu = find_cpu_by_pir(i_core << 3);
+		cpu = find_cpu_by_pir(i_core);
 		if (!cpu)
 			return OPAL_PARAMETER;
 		prlog(PR_DEBUG, "HBRT: Special wakeup release for core"
@@ -774,6 +779,11 @@  static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
 	}
 }
 
+int core_special_wakeup(u32 core, u32 mode)
+{
+	return hservice_wakeup(core, mode);
+}
+
 static struct host_interfaces hinterface = {
 	.interface_version = HOSTBOOT_RUNTIME_INTERFACE_VERSION,
 	.puts = hservice_puts,
diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index a09a636..614b4b1 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -506,6 +506,25 @@  int hservice_i2c_write(uint64_t i_master, uint16_t i_devAddr,
 			 i_offset, i_length, i_data);
 }
 
+int hservice_wakeup(u32 core, u32 mode)
+{
+	int rc;
+	struct opal_prd_msg msg;
+
+	msg.hdr.type = OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP;
+	msg.hdr.size = htobe16(sizeof(msg));
+	msg.spl_wakeup.core = htobe32(core);
+	msg.spl_wakeup.mode = htobe32(mode);
+
+	rc = write(ctx->fd, &msg, sizeof(msg));
+	if (rc != sizeof(msg)) {
+		pr_log(LOG_ERR, "FW:  failed for core %x : %m\n", core);
+		return rc;
+	}
+
+	return 0;
+}
+
 static void ipmi_init(struct opal_prd_ctx *ctx)
 {
 	insert_module("ipmi_devintf");
@@ -1353,9 +1372,24 @@  static int pm_complex_reset(uint64_t chip)
 	return rc;
 }
 
+static bool is_fsp(void)
+{
+	char *path;
+	int rc;
+
+	rc = asprintf(&path, "%s/fsps", devicetree_base);
+	if (rc < 0) {
+		pr_log(LOG_ERR, "PRD: error creating '/fsps' path %m");
+		return false;
+	}
+
+	return access(path, F_OK) ? false : true;
+}
+
 static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
 		struct opal_prd_msg *msg)
 {
+	struct opal_prd_msg omsg;
 	uint32_t proc;
 	int rc;
 
@@ -1365,7 +1399,22 @@  static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
 
 	rc = pm_complex_reset(proc);
 
-	return rc;
+	if (!is_fsp())
+		return rc;
+
+	/* Send only for zz */
+	omsg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS;
+	omsg.hdr.size = htobe16(sizeof(omsg));
+	omsg.occ_reset_status.chip = htobe64(proc);
+	omsg.occ_reset_status.status = htobe64(rc);
+
+	rc = write(ctx->fd, &omsg, sizeof(omsg));
+	if (rc != sizeof(omsg)) {
+		pr_log(LOG_ERR, "FW: Failed to send OCC_RESET status message: %m");
+		return rc;
+	}
+
+	return 0;
 }
 
 static int handle_msg_firmware_notify(struct opal_prd_ctx *ctx,
diff --git a/external/opal-prd/thunk.S b/external/opal-prd/thunk.S
index cca5890..ee3d7c3 100644
--- a/external/opal-prd/thunk.S
+++ b/external/opal-prd/thunk.S
@@ -183,7 +183,7 @@  hinterface:
 	DISABLED_THUNK(hservice_lid_load)
 	DISABLED_THUNK(hservice_lid_unload)
 	CALLBACK_THUNK(hservice_get_reserved_mem)
-	DISABLED_THUNK(hservice_wakeup)
+	CALLBACK_THUNK(hservice_wakeup)
 	CALLBACK_THUNK(hservice_nanosleep)
 	DISABLED_THUNK(hservice_report_occ_failure)
 	CALLBACK_THUNK(hservice_clock_gettime)
diff --git a/hw/occ.c b/hw/occ.c
index 78c6a6a..a53ac92 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -1837,6 +1837,46 @@  out:
 	return rc;
 }
 
+u32 last_seq_id;
+
+int fsp_occ_reset_status(u64 chipid, s64 status)
+{
+	struct fsp_msg *stat;
+	int rc = OPAL_NO_MEM;
+
+	if (status == 0) {
+		stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2, 0, last_seq_id);
+		if (!stat)
+			return rc;
+
+		rc = fsp_queue_msg(stat, fsp_freemsg);
+		if (rc) {
+			fsp_freemsg(stat);
+			log_simple_error(&e_info(OPAL_RC_OCC_RESET),
+				"OCC: Error %d queueing FSP OCC RESET STATUS message\n",
+				rc);
+		}
+	} else {
+		struct proc_chip *chip = get_chip(chipid);
+
+		if (!chip)
+			return OPAL_PARAMETER;
+
+		stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2,
+				 0xfe00 | (chip->pcid & 0xff), last_seq_id);
+		if (!stat)
+			return rc;
+		rc = fsp_queue_msg(stat, fsp_freemsg);
+		if (rc) {
+			fsp_freemsg(stat);
+			log_simple_error(&e_info(OPAL_RC_OCC_RESET),
+			  "OCC: Error %d queueing FSP OCC RESET STATUS message\n",
+				rc);
+		}
+	}
+	return rc;
+}
+
 static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
 {
 	struct fsp_msg *rsp, *stat;
@@ -1877,7 +1917,18 @@  static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
 	 * FSP will request OCC to left in stopped state.
 	 */
 
-	rc = host_services_occ_stop();
+	switch (proc_gen) {
+	case proc_gen_p8:
+		rc = host_services_occ_stop();
+		break;
+	case proc_gen_p9:
+		last_seq_id = seq_id;
+		for_each_chip(chip)
+			prd_occ_reset(chip->id);
+		return;
+	default:
+		return;
+	}
 
 	/* Handle fallback to preload */
 	if (rc == -ENOENT && chip->homer_base) {
diff --git a/hw/prd.c b/hw/prd.c
index d076c19..dcda9c8 100644
--- a/hw/prd.c
+++ b/hw/prd.c
@@ -418,6 +418,14 @@  static int64_t opal_prd_msg(struct opal_prd_msg *msg)
 	case OPAL_PRD_MSG_TYPE_FIRMWARE_REQUEST:
 		rc = prd_msg_handle_firmware_req(msg);
 		break;
+	case OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS:
+		rc = fsp_occ_reset_status(msg->occ_reset_status.chip,
+					  msg->occ_reset_status.status);
+		break;
+	case OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP:
+		rc = core_special_wakeup(msg->spl_wakeup.core,
+					 msg->spl_wakeup.mode);
+		break;
 	default:
 		rc = OPAL_UNSUPPORTED;
 	}
diff --git a/include/opal-api.h b/include/opal-api.h
index 0ff0db0..2f303f9 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -1052,6 +1052,8 @@  enum opal_prd_msg_type {
 	OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE, /* HBRT <-- OPAL */
 	OPAL_PRD_MSG_TYPE_FIRMWARE_NOTIFY, /* HBRT <-- OPAL */
 	OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH, /* HBRT <-- OPAL */
+	OPAL_PRD_MSG_TYPE_OCC_RESET_STATUS, /* HBRT --> OPAL */
+	OPAL_PRD_MSG_TYPE_CORE_SPECIAL_WAKEUP, /* HBRT --> OPAL */
 };
 
 struct opal_prd_msg_header {
@@ -1099,6 +1101,14 @@  struct opal_prd_msg {
 		struct {
 			__be64	chip;
 		} sbe_passthrough;
+		struct {
+			__be64 chip;
+			__be64 status; /* 0 SUCCESS */
+		} occ_reset_status;
+		struct {
+			__be32 core;
+			__be32 mode;
+		} spl_wakeup;
 	};
 };
 
diff --git a/include/skiboot.h b/include/skiboot.h
index 4b7d519..5eb9188 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -317,4 +317,6 @@  extern int occ_sensor_group_clear(u32 group_hndl, int token);
 extern void occ_add_sensor_groups(struct dt_node *sg, u32  *phandles,
 				  int nr_phandles, int chipid);
 
+extern int fsp_occ_reset_status(u64 chipid, s64 status);
+extern int core_special_wakeup(u32 core, u32 mode);
 #endif /* __SKIBOOT_H */