[Skiboot] [PATCH 2/2] opal-prd: occ: Add support for runtime OCC load/start in ZZ

Shilpasri G Bhat shilpa.bhat at linux.vnet.ibm.com
Fri Nov 17 18:22:24 AEDT 2017


This patch adds support to handle OCC load/start event from FSP/PRD.
During IPL we send a success directly to FSP without invoking any HBRT
load routines on recieving OCC load mbox message from FSP. At runtime
we forward this event to host opal-prd.

This patch provides support for invoking OCC load/start HBRT routines
like load_pm_complex() and start_pm_complex() from opal-prd.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
 external/opal-prd/opal-prd.c | 78 ++++++++++++++++++++++++++++++++++++++++++++
 hw/occ.c                     | 66 +++++++++++++++++++++++++++++++------
 hw/prd.c                     | 17 ++++++++++
 include/opal-api.h           |  2 ++
 include/skiboot.h            |  2 ++
 5 files changed, 155 insertions(+), 10 deletions(-)

diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c
index 3fb0459..6ffcac4 100644
--- a/external/opal-prd/opal-prd.c
+++ b/external/opal-prd/opal-prd.c
@@ -303,6 +303,8 @@ extern int call_sbe_message_passing(uint32_t i_chipId);
 extern uint64_t call_get_ipoll_events(void);
 extern int call_firmware_notify(uint64_t len, void *data);
 extern int call_reset_pm_complex(uint64_t chip);
+extern int call_load_pm_complex(u64 chip, u64 homer, u64 occ_common, u32 mode);
+extern int call_start_pm_complex(u64 chip);
 
 void hservice_puts(const char *str)
 {
@@ -1471,6 +1473,79 @@ static int handle_msg_sbe_passthrough(struct opal_prd_ctx *ctx,
 	return rc;
 }
 
+static int pm_complex_load_start(struct opal_prd_ctx *ctx,
+				 struct opal_prd_msg *msg)
+{
+	struct opal_prd_msg omsg;
+	struct prd_range *range;
+	u64 homer, occ_common;
+	u32 proc;
+	int rc;
+
+	proc = be64toh(msg->occ_reset.chip);
+	pr_debug("FW: Firmware requested OCC load for proc 0x%x", proc);
+
+	if (!hservice_runtime->load_pm_complex) {
+		pr_log_nocall("load_pm_complex");
+		rc = -1;
+		goto out;
+	}
+
+	if (!hservice_runtime->start_pm_complex) {
+		pr_log_nocall("start_pm_complex");
+		rc = -1;
+		goto out;
+	}
+
+	range = find_range("ibm,homer-image", proc);
+	if (!range) {
+		pr_log(LOG_ERR, "Homer image not found");
+		rc = -1;
+		goto out;
+	}
+
+	homer = range->physaddr;
+	range = NULL;
+	range = find_range("ibm,occ-common-area", 0);
+	if (!range) {
+		pr_log(LOG_ERR, "occ common area not found");
+		rc = -1;
+		goto out;
+	}
+	occ_common = range->physaddr;
+	pr_debug("PM: calling load_pm_complex(0x%x, 0x%lx, 0x%lx, LOAD)",
+		 proc, homer, occ_common);
+
+	rc = call_load_pm_complex(proc, homer, occ_common, 0);
+	if (rc) {
+		pr_log(LOG_ERR, "PM: load_pm_complex(0x%x) failed %m", proc);
+		goto out;
+	}
+
+	pr_debug("PM: calling start_pm_complex(0x%x)", proc);
+	rc = call_start_pm_complex(proc);
+	if (rc)
+		pr_log(LOG_ERR, "PM: start_pm_complex(0x%x) failed", proc);
+
+out:
+	if (!is_fsp_system())
+		return rc;
+
+	/* Send only for zz */
+	omsg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_LOAD_START_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 rc;
+}
+
 static int handle_prd_msg(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg)
 {
 	int rc = -1;
@@ -1491,6 +1566,9 @@ static int handle_prd_msg(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg)
 	case OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH:
 		rc = handle_msg_sbe_passthrough(ctx, msg);
 		break;
+	case OPAL_PRD_MSG_TYPE_OCC_LOAD_START:
+		rc = pm_complex_load_start(ctx, msg);
+		break;
 	default:
 		pr_log(LOG_WARNING, "Invalid incoming message type 0x%x",
 				msg->hdr.type);
diff --git a/hw/occ.c b/hw/occ.c
index 14f4880..8582faf 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -1748,6 +1748,8 @@ void occ_poke_load_queue(void)
 	}
 }
 
+static u32 last_seq_id;
+static bool in_ipl = true;
 static void occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
 {
 	struct fsp_msg *rsp;
@@ -1780,15 +1782,29 @@ static void occ_do_load(u8 scope, u32 dbob_id __unused, u32 seq_id)
 		return;
 
 	if (proc_gen == proc_gen_p9) {
-		rc = -ENOMEM;
-		/* OCC is pre-loaded in P9, so send SUCCESS to FSP */
-		rsp = fsp_mkmsg(FSP_CMD_LOAD_OCC_STAT, 2, 0, seq_id);
-		if (rsp)
+		if (in_ipl) {
+			/* OCC is pre-loaded in P9, so send SUCCESS to FSP */
+			rsp = fsp_mkmsg(FSP_CMD_LOAD_OCC_STAT, 2, 0, seq_id);
+			if (!rsp)
+				return;
+
 			rc = fsp_queue_msg(rsp, fsp_freemsg);
-		if (rc) {
-			log_simple_error(&e_info(OPAL_RC_OCC_LOAD),
-				"OCC: Error %d queueing FSP OCC LOAD STATUS msg", rc);
-			fsp_freemsg(rsp);
+			if (rc) {
+				log_simple_error(&e_info(OPAL_RC_OCC_LOAD),
+				"OCC: Error %d queueing OCC LOAD STATUS msg",
+						 rc);
+				fsp_freemsg(rsp);
+			}
+			in_ipl = false;
+		} else {
+			struct proc_chip *chip;
+
+			last_seq_id = seq_id;
+			for_each_chip(chip) {
+				if (scope == 0x1 && dbob_id != chip->dbob_id)
+					continue;
+				prd_occ_load_start(chip->id);
+			}
 		}
 		return;
 	}
@@ -1837,8 +1853,6 @@ out:
 	return rc;
 }
 
-static u32 last_seq_id;
-
 int fsp_occ_reset_status(u64 chipid, s64 status)
 {
 	struct fsp_msg *stat;
@@ -1871,6 +1885,38 @@ int fsp_occ_reset_status(u64 chipid, s64 status)
 	return rc;
 }
 
+int fsp_occ_load_start_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 = 0xB500 | (chip->pcid & 0xff);
+		log_simple_error(&e_info(OPAL_RC_OCC_LOAD),
+				 "OCC: Error %d in load/start OCC %lld\n", rc,
+				 chipid);
+	}
+
+	stat = fsp_mkmsg(FSP_CMD_LOAD_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_LOAD),
+			"OCC: Error %d queueing FSP OCC LOAD STATUS msg", rc);
+	}
+
+	return rc;
+}
+
 static void occ_do_reset(u8 scope, u32 dbob_id, u32 seq_id)
 {
 	struct fsp_msg *rsp, *stat;
diff --git a/hw/prd.c b/hw/prd.c
index 253ad24..e426068 100644
--- a/hw/prd.c
+++ b/hw/prd.c
@@ -30,6 +30,7 @@ enum events {
 	EVENT_OCC_ERROR	= 1 << 1,
 	EVENT_OCC_RESET	= 1 << 2,
 	EVENT_SBE_PASSTHROUGH = 1 << 3,
+	EVENT_OCC_LOAD_START = 1 << 4,
 };
 
 static uint8_t events[MAX_CHIPS];
@@ -115,6 +116,10 @@ static void prd_msg_consumed(void *data)
 		proc = msg->sbe_passthrough.chip;
 		event = EVENT_SBE_PASSTHROUGH;
 		break;
+	case OPAL_PRD_MSG_TYPE_OCC_LOAD_START:
+		proc = msg->occ_reset.chip;
+		event = EVENT_OCC_LOAD_START;
+		break;
 	default:
 		prlog(PR_ERR, "PRD: invalid msg consumed, type: 0x%x\n",
 				msg->hdr.type);
@@ -189,6 +194,9 @@ static void send_next_pending_event(void)
 	} else if (event & EVENT_SBE_PASSTHROUGH) {
 		prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH;
 		prd_msg->sbe_passthrough.chip = proc;
+	} else if (event & EVENT_OCC_LOAD_START) {
+		prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_OCC_LOAD_START;
+		prd_msg->occ_reset.chip = proc;
 	}
 
 	/*
@@ -280,6 +288,11 @@ void prd_sbe_passthrough(uint32_t proc)
 	prd_event(proc, EVENT_SBE_PASSTHROUGH);
 }
 
+void prd_occ_load_start(uint32_t proc)
+{
+	prd_event(proc, EVENT_OCC_LOAD_START);
+}
+
 /* incoming message handlers */
 static int prd_msg_handle_attn_ack(struct opal_prd_msg *msg)
 {
@@ -439,6 +452,10 @@ static int64_t opal_prd_msg(struct opal_prd_msg *msg)
 		rc = hservice_wakeup_p9(msg->spl_wakeup.core,
 					msg->spl_wakeup.mode);
 		break;
+	case OPAL_PRD_MSG_TYPE_OCC_LOAD_START_STATUS:
+		rc = fsp_occ_load_start_status(msg->occ_reset_status.chip,
+					       msg->occ_reset_status.status);
+		break;
 	default:
 		rc = OPAL_UNSUPPORTED;
 	}
diff --git a/include/opal-api.h b/include/opal-api.h
index 9c9d7fb..3cfb43f 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -1056,6 +1056,8 @@ enum opal_prd_msg_type {
 	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 */
+	OPAL_PRD_MSG_TYPE_OCC_LOAD_START, /* HBRT --> OPAL */
+	OPAL_PRD_MSG_TYPE_OCC_LOAD_START_STATUS, /* HBRT --> OPAL */
 };
 
 struct opal_prd_msg_header {
diff --git a/include/skiboot.h b/include/skiboot.h
index 221ed4b..2131e4a 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -293,6 +293,7 @@ extern void prd_occ_reset(uint32_t proc);
 extern void prd_sbe_passthrough(uint32_t proc);
 extern void prd_init(void);
 extern void prd_register_reserved_memory(void);
+extern void prd_occ_load_start(u32 proc);
 
 /* Flatten device-tree */
 extern void *create_dtb(const struct dt_node *root, bool exclusive);
@@ -335,4 +336,5 @@ extern void occ_add_sensor_groups(struct dt_node *sg, u32  *phandles,
 
 extern int fsp_occ_reset_status(u64 chipid, s64 status);
 extern int core_special_wakeup(u32 core, u32 mode);
+extern int fsp_occ_load_start_status(u64 chipid, s64 status);
 #endif /* __SKIBOOT_H */
-- 
1.8.3.1



More information about the Skiboot mailing list