[1/2] opal-prd: Add support for runtime OCC reset in ZZ

Message ID 1510903344-31008-2-git-send-email-shilpa.bhat@linux.vnet.ibm.com
State New
Headers show
Series
  • Support runtime OCC reset/load in ZZ
Related show

Commit Message

Shilpasri G Bhat Nov. 17, 2017, 7:22 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>
---
 core/direct-controls.c       | 31 +++++++++++++++++++++++++++--
 core/hostservices.c          | 30 ++++++++++++++++++++++++++++
 external/opal-prd/opal-prd.c | 40 ++++++++++++++++++++++++++++++++++++-
 external/opal-prd/thunk.S    |  2 +-
 hw/occ.c                     | 47 +++++++++++++++++++++++++++++++++++++++++++-
 hw/prd.c                     |  9 +++++++++
 include/cpu.h                |  4 ++++
 include/hostservices.h       |  1 +
 include/opal-api.h           | 10 ++++++++++
 include/skiboot.h            |  2 ++
 10 files changed, 171 insertions(+), 5 deletions(-)

Comments

Vasant Hegde Nov. 27, 2017, 8:59 a.m. | #1
On 11/17/2017 12:52 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>

I have one minor comment on this patch (somehow I missed this earlier). 
Otherwise patch looks good to me.

Reviewed-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>



> ---
>  core/direct-controls.c       | 31 +++++++++++++++++++++++++++--
>  core/hostservices.c          | 30 ++++++++++++++++++++++++++++
>  external/opal-prd/opal-prd.c | 40 ++++++++++++++++++++++++++++++++++++-
>  external/opal-prd/thunk.S    |  2 +-
>  hw/occ.c                     | 47 +++++++++++++++++++++++++++++++++++++++++++-
>  hw/prd.c                     |  9 +++++++++
>  include/cpu.h                |  4 ++++
>  include/hostservices.h       |  1 +
>  include/opal-api.h           | 10 ++++++++++
>  include/skiboot.h            |  2 ++
>  10 files changed, 171 insertions(+), 5 deletions(-)
>

.../...

>
>  enum events {
>  	EVENT_ATTN	= 1 << 0,
> @@ -430,6 +431,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 = hservice_wakeup_p9(msg->spl_wakeup.core,
> +					msg->spl_wakeup.mode);

Consider renaming hservice_wakeup call like below.

Looks like existing hservice_wakeup() in hostservice.c is specific to P8. So 
rename function like
	hservice_wakeup_p8 and hservice_wakeup_p9 and have global wrapper function 
hservice_wakeup().

-Vasant

Patch

diff --git a/core/direct-controls.c b/core/direct-controls.c
index 512cb36..62f9824 100644
--- a/core/direct-controls.c
+++ b/core/direct-controls.c
@@ -220,7 +220,7 @@  static int p9_sreset_thread(struct cpu_thread *cpu)
 	return 0;
 }
 
-static int dctl_set_special_wakeup(struct cpu_thread *t)
+int dctl_set_special_wakeup(struct cpu_thread *t)
 {
 	struct cpu_thread *c = t->primary;
 	int rc = OPAL_SUCCESS;
@@ -238,7 +238,7 @@  static int dctl_set_special_wakeup(struct cpu_thread *t)
 	return rc;
 }
 
-static int dctl_clear_special_wakeup(struct cpu_thread *t)
+int dctl_clear_special_wakeup(struct cpu_thread *t)
 {
 	struct cpu_thread *c = t->primary;
 	int rc = OPAL_SUCCESS;
@@ -259,6 +259,33 @@  out:
 	return rc;
 }
 
+int dctl_clear_all_special_wakeup(void)
+{
+	struct proc_chip *chip;
+	struct cpu_thread *c;
+	int rc;
+
+	if (proc_gen != proc_gen_p9)
+		return OPAL_UNSUPPORTED;
+
+	for_each_chip(chip)
+		for_each_available_core_in_chip(c, chip->id) {
+			lock(&c->dctl_lock);
+			if (c->special_wakeup_count) {
+				rc = p9_core_clear_special_wakeup(c);
+				if (!rc) {
+					c->special_wakeup_count = 0;
+				} else {
+					unlock(&c->dctl_lock);
+					return rc;
+				}
+			}
+			unlock(&c->dctl_lock);
+		}
+
+	return OPAL_SUCCESS;
+}
+
 static int dctl_stop(struct cpu_thread *t)
 {
 	struct cpu_thread *c = t->primary;
diff --git a/core/hostservices.c b/core/hostservices.c
index dd8cae2..be5f6c2 100644
--- a/core/hostservices.c
+++ b/core/hostservices.c
@@ -755,6 +755,36 @@  static int hservice_wakeup(uint32_t i_core, uint32_t i_mode)
 	}
 }
 
+int hservice_wakeup_p9(u32 core, u32 mode)
+{
+	struct cpu_thread *cpu;
+
+	core &= SPR_PIR_P9_MASK;
+	core <<= 2;
+
+	switch (mode) {
+	case 0: /* Assert special wakeup */
+		cpu = find_cpu_by_pir(core);
+		if (!cpu)
+			return OPAL_PARAMETER;
+		prlog(PR_DEBUG, "HBRT: Special wakeup assert for core 0x%x,"
+		      " count=%d\n", core, cpu->special_wakeup_count);
+		return dctl_set_special_wakeup(cpu);
+	case 1: /* Deassert special wakeup */
+		cpu = find_cpu_by_pir(core);
+		if (!cpu)
+			return OPAL_PARAMETER;
+		prlog(PR_DEBUG, "HBRT: Special wakeup release for core"
+		      " 0x%x, count=%d\n", core, cpu->special_wakeup_count);
+		return dctl_clear_special_wakeup(cpu);
+	case 2: /* Clear all special wakeups */
+		prlog(PR_DEBUG, "HBRT: Special wakeup release for all cores\n");
+		return dctl_clear_all_special_wakeup();
+	default:
+		return OPAL_PARAMETER;
+	}
+}
+
 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 b15063f..3fb0459 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -524,6 +524,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");
@@ -1383,6 +1402,7 @@  static int pm_complex_reset(uint64_t chip)
 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;
 
@@ -1392,7 +1412,22 @@  static int handle_msg_occ_reset(struct opal_prd_ctx *ctx,
 
 	rc = pm_complex_reset(proc);
 
-	return rc;
+	if (!is_fsp_system())
+		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,
@@ -1988,6 +2023,9 @@  static int run_prd_daemon(struct opal_prd_ctx *ctx)
 		hinterface.pnor_write = NULL;
 	}
 
+	if (!is_fsp_system())
+		hinterface.wakeup = NULL;
+
 	ipmi_init(ctx);
 
 	pr_debug("HBRT: calling hservices_init");
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..14f4880 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -1837,6 +1837,40 @@  out:
 	return rc;
 }
 
+static u32 last_seq_id;
+
+int fsp_occ_reset_status(u64 chipid, s64 status)
+{
+	struct fsp_msg *stat;
+	int rc = OPAL_NO_MEM;
+	int status_word = 0;
+
+	if (status) {
+		struct proc_chip *chip = get_chip(chipid);
+
+		if (!chip)
+			return OPAL_PARAMETER;
+
+		status_word = 0xfe00 | (chip->pcid & 0xff);
+		log_simple_error(&e_info(OPAL_RC_OCC_RESET),
+				 "OCC: Error %lld in OCC reset of chip %lld\n",
+				 status, chipid);
+	}
+
+	stat = fsp_mkmsg(FSP_CMD_RESET_OCC_STAT, 2, status_word, 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 +1911,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 c00e10a..253ad24 100644
--- a/hw/prd.c
+++ b/hw/prd.c
@@ -23,6 +23,7 @@ 
 #include <fsp.h>
 #include <mem_region.h>
 #include <prd-fw-msg.h>
+#include <hostservices.h>
 
 enum events {
 	EVENT_ATTN	= 1 << 0,
@@ -430,6 +431,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 = hservice_wakeup_p9(msg->spl_wakeup.core,
+					msg->spl_wakeup.mode);
+		break;
 	default:
 		rc = OPAL_UNSUPPORTED;
 	}
diff --git a/include/cpu.h b/include/cpu.h
index 168fa99..87c397f 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -284,4 +284,8 @@  extern void cpu_idle_delay(unsigned long delay);
 extern void cpu_set_radix_mode(void);
 extern void cpu_fast_reboot_complete(void);
 
+int dctl_set_special_wakeup(struct cpu_thread *t);
+int dctl_clear_special_wakeup(struct cpu_thread *t);
+int dctl_clear_all_special_wakeup(void);
+
 #endif /* __CPU_H */
diff --git a/include/hostservices.h b/include/hostservices.h
index 62ef04b..b7d54a0 100644
--- a/include/hostservices.h
+++ b/include/hostservices.h
@@ -40,4 +40,5 @@  int find_master_and_slave_occ(uint64_t **master, uint64_t **slave,
 			      int *nr_masters, int *nr_slaves);
 int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data);
 
+int hservice_wakeup_p9(u32 core, u32 mode);
 #endif /* __HOSTSERVICES_H */
diff --git a/include/opal-api.h b/include/opal-api.h
index 0bc036e..9c9d7fb 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -1054,6 +1054,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 {
@@ -1101,6 +1103,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 db91325..221ed4b 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -333,4 +333,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 */