[Skiboot] [PATCH RFC 11/12] prd: Implement firmware side of opaque PRD channel

Jeremy Kerr jk at ozlabs.org
Thu May 25 17:05:54 AEST 2017


This change introduces the firmware side of the opaque HBRT <--> OPAL
message channel. We define a base message format to be shared with HBRT
(in include/prd-fw-msg.h), and allow firmware requests and responses to
be sent over this channel.

We don't currently have any notifications defined, so have nothing to do
for firmware_notify() at this stage.

Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
CC: Daniel M Crowell <dcrowell at us.ibm.com>
---
 hw/prd.c             | 88 +++++++++++++++++++++++++++++++++++++++++++++-------
 include/prd-fw-msg.h | 37 ++++++++++++++++++++++
 2 files changed, 113 insertions(+), 12 deletions(-)
 create mode 100644 include/prd-fw-msg.h

diff --git a/hw/prd.c b/hw/prd.c
index 0db7e6b..da38e3a 100644
--- a/hw/prd.c
+++ b/hw/prd.c
@@ -22,6 +22,7 @@
 #include <opal-msg.h>
 #include <fsp.h>
 #include <mem_region.h>
+#include <prd-fw-msg.h>
 
 enum events {
 	EVENT_ATTN	= 1 << 0,
@@ -31,7 +32,9 @@ enum events {
 
 static uint8_t events[MAX_CHIPS];
 static uint64_t ipoll_status[MAX_CHIPS];
-static struct opal_prd_msg prd_msg;
+static uint8_t _prd_msg_buf[sizeof(struct opal_prd_msg) +
+			    sizeof(struct prd_fw_msg)];
+static struct opal_prd_msg *prd_msg = (struct opal_prd_msg *)&_prd_msg_buf;
 static bool prd_msg_inuse, prd_active;
 static struct dt_node *prd_node;
 static bool prd_enabled = false;
@@ -104,6 +107,8 @@ static void prd_msg_consumed(void *data)
 		proc = msg->occ_reset.chip;
 		event = EVENT_OCC_RESET;
 		break;
+	case OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE:
+		break;
 	default:
 		prlog(PR_ERR, "PRD: invalid msg consumed, type: 0x%x\n",
 				msg->hdr.type);
@@ -162,18 +167,18 @@ static void send_next_pending_event(void)
 		return;
 
 	prd_msg_inuse = true;
-	prd_msg.token = 0;
-	prd_msg.hdr.size = sizeof(prd_msg);
+	prd_msg->token = 0;
+	prd_msg->hdr.size = sizeof(*prd_msg);
 
 	if (event & EVENT_ATTN) {
-		prd_msg.hdr.type = OPAL_PRD_MSG_TYPE_ATTN;
-		populate_ipoll_msg(&prd_msg, proc);
+		prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_ATTN;
+		populate_ipoll_msg(prd_msg, proc);
 	} else if (event & EVENT_OCC_ERROR) {
-		prd_msg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_ERROR;
-		prd_msg.occ_error.chip = proc;
+		prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_OCC_ERROR;
+		prd_msg->occ_error.chip = proc;
 	} else if (event & EVENT_OCC_RESET) {
-		prd_msg.hdr.type = OPAL_PRD_MSG_TYPE_OCC_RESET;
-		prd_msg.occ_reset.chip = proc;
+		prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_OCC_RESET;
+		prd_msg->occ_reset.chip = proc;
 		occ_msg_queue_occ_reset();
 	}
 
@@ -182,8 +187,8 @@ static void send_next_pending_event(void)
 	 * disabled then we shouldn't propagate PRD events to the host.
 	 */
 	if (prd_enabled)
-		_opal_queue_msg(OPAL_MSG_PRD, &prd_msg, prd_msg_consumed, 4,
-				(uint64_t *) &prd_msg);
+		_opal_queue_msg(OPAL_MSG_PRD, prd_msg, prd_msg_consumed, 4,
+				(uint64_t *)prd_msg);
 }
 
 static void __prd_event(uint32_t proc, uint8_t event)
@@ -316,6 +321,62 @@ static int prd_msg_handle_fini(void)
 	return OPAL_SUCCESS;
 }
 
+static int prd_msg_handle_firmware_req(struct opal_prd_msg *msg)
+{
+	unsigned long fw_req_len, fw_resp_len;
+	struct prd_fw_msg *fw_req, *fw_resp;
+	int rc;
+
+	fw_req_len = be64_to_cpu(msg->fw_req.req_len);
+	fw_resp_len = be64_to_cpu(msg->fw_req.resp_len);
+	fw_req = (struct prd_fw_msg *)msg->fw_req.data;
+
+	/* do we have a full firmware message? */
+	if (fw_req_len < sizeof(struct prd_fw_msg))
+		return -EINVAL;
+
+	/* does the total (outer) PRD message len provide enough data for the
+	 * claimed (inner) FW message?
+	 */
+	if (msg->hdr.size < fw_req_len +
+			offsetof(struct opal_prd_msg, fw_req.data))
+		return -EINVAL;
+
+	/* is there enough response buffer for a base response? Type-specific
+	 * responses may be larger, but anything less than BASE_SIZE is
+	 * invalid. */
+	if (fw_resp_len < PRD_FW_MSG_BASE_SIZE)
+		return -EINVAL;
+
+	/* prepare a response message. */
+	lock(&events_lock);
+	prd_msg_inuse = true;
+	prd_msg->token = 0;
+	prd_msg->hdr.type = OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE;
+	fw_resp = (void *)prd_msg->fw_resp.data;
+
+	switch (be64_to_cpu(fw_req->type)) {
+	case PRD_FW_MSG_TYPE_REQ_NOP:
+		fw_resp->type = cpu_to_be64(PRD_FW_MSG_TYPE_RESP_NOP);
+		prd_msg->fw_resp.len = cpu_to_be64(PRD_FW_MSG_BASE_SIZE);
+		prd_msg->hdr.size = cpu_to_be16(sizeof(*prd_msg));
+		rc = 0;
+		break;
+	default:
+		rc = -ENOSYS;
+	}
+
+	if (!rc)
+		rc = _opal_queue_msg(OPAL_MSG_PRD, prd_msg, prd_msg_consumed, 4,
+				(uint64_t *) prd_msg);
+	else
+		prd_msg_inuse = false;
+
+	unlock(&events_lock);
+
+	return rc;
+}
+
 /* Entry from the host above */
 static int64_t opal_prd_msg(struct opal_prd_msg *msg)
 {
@@ -328,7 +389,7 @@ static int64_t opal_prd_msg(struct opal_prd_msg *msg)
 			msg->hdr.type == OPAL_PRD_MSG_TYPE_FINI)
 		return prd_msg_handle_fini();
 
-	if (msg->hdr.size != sizeof(*msg))
+	if (msg->hdr.size < sizeof(*msg))
 		return OPAL_PARAMETER;
 
 	switch (msg->hdr.type) {
@@ -341,6 +402,9 @@ static int64_t opal_prd_msg(struct opal_prd_msg *msg)
 	case OPAL_PRD_MSG_TYPE_OCC_RESET_NOTIFY:
 		rc = occ_msg_queue_occ_reset();
 		break;
+	case OPAL_PRD_MSG_TYPE_FIRMWARE_REQUEST:
+		rc = prd_msg_handle_firmware_req(msg);
+		break;
 	default:
 		rc = OPAL_UNSUPPORTED;
 	}
diff --git a/include/prd-fw-msg.h b/include/prd-fw-msg.h
new file mode 100644
index 0000000..c00405d
--- /dev/null
+++ b/include/prd-fw-msg.h
@@ -0,0 +1,37 @@
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef __PRD_FW_MSG_H
+#define __PRD_FW_MSG_H
+
+#include <types.h>
+
+/* Messaging structure for the opaque channel between OPAL and HBRT. This
+ * format is used for the firmware_request and firmware_notify interfaces
+ */
+enum {
+	PRD_FW_MSG_TYPE_REQ_NOP = 0,
+	PRD_FW_MSG_TYPE_RESP_NOP = 1,
+};
+
+struct prd_fw_msg {
+	__be64		type;
+};
+
+#define PRD_FW_MSG_BASE_SIZE	sizeof(__be64)
+
+#endif /* __PRD_FW_MSG_H */
-- 
2.7.4



More information about the Skiboot mailing list