aboutsummaryrefslogtreecommitdiff
path: root/hw/prd.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/prd.c')
-rw-r--r--hw/prd.c77
1 files changed, 76 insertions, 1 deletions
diff --git a/hw/prd.c b/hw/prd.c
index 042d977..fea8cf0 100644
--- a/hw/prd.c
+++ b/hw/prd.c
@@ -40,6 +40,7 @@ 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 struct opal_prd_msg *prd_msg_fsp_req;
+static struct opal_prd_msg *prd_msg_fsp_notify;
static bool prd_msg_inuse, prd_active;
static struct dt_node *prd_node;
static bool prd_enabled = false;
@@ -82,10 +83,11 @@ static uint64_t prd_ipoll_mask;
static void send_next_pending_event(void);
-static void prd_msg_consumed(void *data, int status __unused)
+static void prd_msg_consumed(void *data, int status)
{
struct opal_prd_msg *msg = data;
uint32_t proc;
+ int notify_status = OPAL_SUCCESS;
uint8_t event = 0;
lock(&events_lock);
@@ -118,6 +120,18 @@ static void prd_msg_consumed(void *data, int status __unused)
prd_msg_fsp_req = NULL;
}
break;
+ case OPAL_PRD_MSG_TYPE_FIRMWARE_NOTIFY:
+ if (prd_msg_fsp_notify) {
+ free(prd_msg_fsp_notify);
+ prd_msg_fsp_notify = NULL;
+ }
+ if (status != 0) {
+ prlog(PR_DEBUG,
+ "PRD: Failed to send FSP -> HBRT message\n");
+ notify_status = FSP_STATUS_GENERIC_FAILURE;
+ }
+ hservice_hbrt_msg_response(notify_status);
+ break;
case OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH:
proc = msg->sbe_passthrough.chip;
event = EVENT_SBE_PASSTHROUGH;
@@ -356,6 +370,67 @@ void prd_fw_resp_fsp_response(int status)
unlock(&events_lock);
}
+int prd_hbrt_fsp_msg_notify(void *data, u32 dsize)
+{
+ int size;
+ int rc = FSP_STATUS_GENERIC_FAILURE;
+ enum opal_msg_type msg_type = OPAL_MSG_PRD2;
+
+ if (!prd_enabled || !prd_active) {
+ prlog(PR_NOTICE, "PRD: PRD daemon is not ready\n");
+ return rc;
+ }
+
+ /* Calculate prd message size */
+ size = sizeof(prd_msg->hdr) + sizeof(prd_msg->token) +
+ sizeof(prd_msg->fw_notify) + dsize;
+
+ if (size > OPAL_PRD_MSG_SIZE_MAX) {
+ prlog(PR_DEBUG, "PRD: FSP - HBRT notify message size (0x%x)"
+ " is bigger than prd interface can handle\n", size);
+ return rc;
+ }
+
+ lock(&events_lock);
+
+ /* FSP - HBRT messages are serialized */
+ if (prd_msg_fsp_notify) {
+ prlog(PR_DEBUG, "PRD: FSP - HBRT notify message is busy\n");
+ goto unlock_events;
+ }
+
+ /* Handle message allocation */
+ prd_msg_fsp_notify = zalloc(size);
+ if (!prd_msg_fsp_notify) {
+ prlog(PR_DEBUG,
+ "PRD: %s: Failed to allocate memory.\n", __func__);
+ goto unlock_events;
+ }
+
+ prd_msg_fsp_notify->hdr.type = OPAL_PRD_MSG_TYPE_FIRMWARE_NOTIFY;
+ prd_msg_fsp_notify->hdr.size = cpu_to_be16(size);
+ prd_msg_fsp_notify->token = 0;
+ prd_msg_fsp_notify->fw_notify.len = cpu_to_be64(dsize);
+ memcpy(&(prd_msg_fsp_notify->fw_notify.data), data, dsize);
+
+ /*
+ * If prd message size is <= OPAL_MSG_FIXED_PARAMS_SIZE then use
+ * OPAL_MSG_PRD to pass data to kernel. So that it works fine on
+ * older kernel (which does not support OPAL_MSG_PRD2).
+ */
+ if (prd_msg_fsp_notify->hdr.size < OPAL_MSG_FIXED_PARAMS_SIZE)
+ msg_type = OPAL_MSG_PRD;
+
+ rc = _opal_queue_msg(msg_type, prd_msg_fsp_notify,
+ prd_msg_consumed, size, prd_msg_fsp_notify);
+ if (!rc)
+ prd_msg_inuse = true;
+
+unlock_events:
+ unlock(&events_lock);
+ return rc;
+}
+
/* incoming message handlers */
static int prd_msg_handle_attn_ack(struct opal_prd_msg *msg)
{