aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasant Hegde <hegdevasant@linux.vnet.ibm.com>2019-05-28 11:17:25 +0530
committerStewart Smith <stewart@linux.ibm.com>2019-06-03 10:28:57 +1000
commitfb702bf01aeabab92d3830d90c8060e5cbd57258 (patch)
treeebaf1f8d5928b3313a2dc25d62d5ccb26f8f42ea
parentfcb1d4dc1b9dd2bd98bdd70bff20f0de33231ee5 (diff)
downloadskiboot-fb702bf01aeabab92d3830d90c8060e5cbd57258.zip
skiboot-fb702bf01aeabab92d3830d90c8060e5cbd57258.tar.gz
skiboot-fb702bf01aeabab92d3830d90c8060e5cbd57258.tar.bz2
prd: Implement generic HBRT - FSP interface
This patch implements generic interface to pass data from HBRT to FSP during runtime (HBRT -> opal-prd -> kernel -> OPAL -> FSP). HBRT sends data via firmware_request interface. We have to convert that to MBOX format and send it to FSP. OPAL uses TCE mapped memory to send data. FSP will reuse same memory for response. Once processing is complete FSP sends response to OPAL. Finally OPAL calls HBRT with firmware_response message. Also introduces new opal_msg type (OPAL_MSG_PRD2) to pass bigger prd message to kernel. - if (prd_msg > OPAL_MSG_FIXED_PARAMS_SIZE) use OPAL_MSG_PRD2 Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
-rw-r--r--core/hostservices.c77
-rw-r--r--doc/opal-api/opal-messages.rst6
-rw-r--r--hw/prd.c130
-rw-r--r--include/fsp.h6
-rw-r--r--include/hostservices.h1
-rw-r--r--include/opal-api.h3
-rw-r--r--include/prd-fw-msg.h3
-rw-r--r--include/psi.h7
-rw-r--r--include/skiboot.h1
9 files changed, 233 insertions, 1 deletions
diff --git a/core/hostservices.c b/core/hostservices.c
index d3a9b3c..bf1b308 100644
--- a/core/hostservices.c
+++ b/core/hostservices.c
@@ -802,3 +802,80 @@ bool hservices_init(void)
return true;
}
+
+static void hservice_send_hbrt_msg_resp(struct fsp_msg *msg)
+{
+ int status = (msg->resp->word1 >> 8) & 0xff;
+
+ fsp_freemsg(msg);
+ if (status) {
+ prlog(PR_NOTICE, "HBRT: HBRT to FSP MBOX command failed "
+ "[rc=0x%x]\n", status);
+ }
+
+ fsp_tce_unmap(PSI_DMA_HBRT_FSP_MSG, PSI_DMA_HBRT_FSP_MSG_SIZE);
+ /* Send response data to HBRT */
+ prd_fw_resp_fsp_response(status);
+}
+
+#define FSP_STATUS_RR (-8193)
+/* Caller takes care of serializing MBOX message */
+int hservice_send_hbrt_msg(void *data, u64 dsize)
+{
+ uint32_t tce_len, offset;
+ int rc;
+ uint64_t addr;
+ struct fsp_msg *msg;
+
+ prlog(PR_NOTICE, "HBRT: HBRT - FSP message generated\n");
+
+ /* We only support FSP based system */
+ if (!fsp_present()) {
+ prlog(PR_DEBUG,
+ "HBRT: Warning, HBRT - FSP message discarded!\n");
+ return OPAL_UNSUPPORTED;
+ }
+
+ /*
+ * If FSP is in R/R then send specific return code to HBRT (inside
+ * HBRT message) and return success to caller (opal_prd_msg()).
+ */
+ if (fsp_in_rr()) {
+ prlog(PR_DEBUG,
+ "HBRT: FSP is in R/R. Dropping HBRT - FSP message\n");
+ prd_fw_resp_fsp_response(FSP_STATUS_RR);
+ return OPAL_SUCCESS;
+ }
+
+ /* Adjust address, size for TCE mapping */
+ addr = (u64)data & ~TCE_MASK;
+ offset = (u64)data & TCE_MASK;
+ tce_len = ALIGN_UP((dsize + offset), TCE_PSIZE);
+
+ if (tce_len > PSI_DMA_HBRT_FSP_MSG_SIZE) {
+ prlog(PR_DEBUG,
+ "HBRT: HBRT - FSP message is too big, discarded\n");
+ return OPAL_PARAMETER;
+ }
+ fsp_tce_map(PSI_DMA_HBRT_FSP_MSG, (void *)addr, tce_len);
+
+ msg = fsp_mkmsg(FSP_CMD_HBRT_TO_FSP, 3, 0,
+ (PSI_DMA_HBRT_FSP_MSG + offset), dsize);
+ if (!msg) {
+ prlog(PR_DEBUG,
+ "HBRT: Failed to create HBRT - FSP message to FSP\n");
+ rc = OPAL_NO_MEM;
+ goto out_tce_unmap;
+ }
+
+ rc = fsp_queue_msg(msg, hservice_send_hbrt_msg_resp);
+ if (rc == 0)
+ return rc;
+
+ prlog(PR_DEBUG, "HBRT: Failed to queue HBRT message to FSP\n");
+ fsp_freemsg(msg);
+
+out_tce_unmap:
+ fsp_tce_unmap(PSI_DMA_HBRT_FSP_MSG, PSI_DMA_HBRT_FSP_MSG_SIZE);
+ return rc;
+}
diff --git a/doc/opal-api/opal-messages.rst b/doc/opal-api/opal-messages.rst
index c7b2e5c..1f5d6f2 100644
--- a/doc/opal-api/opal-messages.rst
+++ b/doc/opal-api/opal-messages.rst
@@ -227,3 +227,9 @@ these values.
If ``opal_occ_msg.type > 2`` then host should ignore the message for now,
new events can be defined for ``opal_occ_msg.type`` in the future versions
of OPAL.
+
+OPAL_MSG_PRD2
+-------------
+
+This message is a OPAL-to-HBRT notification. Its same as OPAL_MSG_PRD except
+this one supports passing more than 64bytes (8*8) of data.
diff --git a/hw/prd.c b/hw/prd.c
index 87e1bae..042d977 100644
--- a/hw/prd.c
+++ b/hw/prd.c
@@ -39,6 +39,7 @@ static uint64_t ipoll_status[MAX_CHIPS];
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 bool prd_msg_inuse, prd_active;
static struct dt_node *prd_node;
static bool prd_enabled = false;
@@ -112,6 +113,10 @@ static void prd_msg_consumed(void *data, int status __unused)
event = EVENT_OCC_RESET;
break;
case OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE:
+ if (prd_msg_fsp_req) {
+ free(prd_msg_fsp_req);
+ prd_msg_fsp_req = NULL;
+ }
break;
case OPAL_PRD_MSG_TYPE_SBE_PASSTHROUGH:
proc = msg->sbe_passthrough.chip;
@@ -309,6 +314,48 @@ void prd_fsp_occ_load_start(uint32_t proc)
prd_event(proc, EVENT_FSP_OCC_LOAD_START);
}
+void prd_fw_resp_fsp_response(int status)
+{
+ struct prd_fw_msg *fw_resp;
+ uint64_t fw_resp_len_old;
+ int rc;
+ uint16_t hdr_size;
+ enum opal_msg_type msg_type = OPAL_MSG_PRD2;
+
+ lock(&events_lock);
+
+ /* In case of failure, return code is passed via generic_resp */
+ if (status != 0) {
+ fw_resp = (struct prd_fw_msg *)prd_msg_fsp_req->fw_resp.data;
+ fw_resp->type = cpu_to_be64(PRD_FW_MSG_TYPE_RESP_GENERIC);
+ fw_resp->generic_resp.status = cpu_to_be64(status);
+
+ fw_resp_len_old = prd_msg_fsp_req->fw_resp.len;
+ prd_msg_fsp_req->fw_resp.len = cpu_to_be64(PRD_FW_MSG_BASE_SIZE +
+ sizeof(fw_resp->generic_resp));
+
+ /* Update prd message size */
+ hdr_size = be16_to_cpu(prd_msg_fsp_req->hdr.size);
+ hdr_size -= fw_resp_len_old;
+ hdr_size += be64_to_cpu(prd_msg_fsp_req->fw_resp.len);
+ prd_msg_fsp_req->hdr.size = cpu_to_be16(hdr_size);
+ }
+
+ /*
+ * 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_req->hdr.size < OPAL_MSG_FIXED_PARAMS_SIZE)
+ msg_type = OPAL_MSG_PRD;
+
+ rc = _opal_queue_msg(msg_type, prd_msg_fsp_req, prd_msg_consumed,
+ prd_msg_fsp_req->hdr.size, prd_msg_fsp_req);
+ if (!rc)
+ prd_msg_inuse = true;
+ unlock(&events_lock);
+}
+
/* incoming message handlers */
static int prd_msg_handle_attn_ack(struct opal_prd_msg *msg)
{
@@ -366,9 +413,10 @@ static int prd_msg_handle_fini(void)
static int prd_msg_handle_firmware_req(struct opal_prd_msg *msg)
{
- unsigned long fw_req_len, fw_resp_len;
+ unsigned long fw_req_len, fw_resp_len, data_len;
struct prd_fw_msg *fw_req, *fw_resp;
int rc;
+ uint64_t resp_msg_size;
fw_req_len = be64_to_cpu(msg->fw_req.req_len);
fw_resp_len = be64_to_cpu(msg->fw_req.resp_len);
@@ -417,6 +465,86 @@ static int prd_msg_handle_firmware_req(struct opal_prd_msg *msg)
prd_msg->hdr.size = cpu_to_be16(sizeof(*prd_msg));
rc = 0;
break;
+ case PRD_FW_MSG_TYPE_HBRT_FSP:
+ /*
+ * HBRT -> FSP messages are serialized. Just to be sure check
+ * whether fsp_req message is free or not.
+ */
+ if (prd_msg_fsp_req) {
+ prlog(PR_DEBUG, "PRD: HBRT - FSP message is busy\n");
+ rc = OPAL_BUSY;
+ break;
+ }
+
+ /*
+ * FSP interface doesn't tell us the response data size.
+ * Hence pass response length = request length.
+ */
+ resp_msg_size = sizeof(msg->hdr) + sizeof(msg->token) +
+ sizeof(msg->fw_resp) + fw_req_len;
+
+ if (resp_msg_size > OPAL_PRD_MSG_SIZE_MAX) {
+ prlog(PR_DEBUG, "PRD: HBRT - FSP response size (0x%llx)"
+ " is bigger than prd interface can handle\n",
+ resp_msg_size);
+ rc = OPAL_INTERNAL_ERROR;
+ break;
+ }
+
+ /*
+ * We will use fsp_queue_msg() to pass HBRT data to FSP.
+ * We cannot directly map kernel passed data as kernel
+ * will release the memory as soon as we return the control.
+ * Also FSP uses same memory to pass response to HBRT. Hence
+ * lets copy data to local memory. Then pass this memory to
+ * FSP via TCE mapping.
+ */
+ prd_msg_fsp_req = zalloc(resp_msg_size);
+ if (!prd_msg_fsp_req) {
+ prlog(PR_DEBUG, "PRD: Failed to allocate memory "
+ "for HBRT - FSP message\n");
+ rc = OPAL_RESOURCE;
+ break;
+ }
+
+ /* Update message header */
+ prd_msg_fsp_req->hdr.type = OPAL_PRD_MSG_TYPE_FIRMWARE_RESPONSE;
+ prd_msg_fsp_req->hdr.size = cpu_to_be16(resp_msg_size);
+ prd_msg_fsp_req->token = 0;
+ prd_msg_fsp_req->fw_resp.len = fw_req_len;
+
+ /* copy HBRT data to local memory */
+ fw_resp = (struct prd_fw_msg *)prd_msg_fsp_req->fw_resp.data;
+ memcpy(fw_resp, fw_req, fw_req_len);
+
+ /* Update response type */
+ fw_resp->type = cpu_to_be64(PRD_FW_MSG_TYPE_HBRT_FSP);
+
+ /* Get MBOX message size */
+ data_len = fw_req_len - PRD_FW_MSG_BASE_SIZE;
+
+ /* We have to wait until FSP responds */
+ prd_msg_inuse = false;
+ /* Unlock to avoid recursive lock issue */
+ unlock(&events_lock);
+
+ /* Send message to FSP */
+ rc = hservice_send_hbrt_msg(&(fw_resp->mbox_msg), data_len);
+
+ /*
+ * Callback handler from hservice_send_hbrt_msg will take
+ * care of sending response to HBRT. So just send return
+ * code to Linux.
+ */
+ if (rc == OPAL_SUCCESS)
+ return rc;
+
+ lock(&events_lock);
+ if (prd_msg_fsp_req) {
+ free(prd_msg_fsp_req);
+ prd_msg_fsp_req = NULL;
+ }
+ break;
default:
prlog(PR_DEBUG, "PRD: Unsupported fw_request type : 0x%llx\n",
be64_to_cpu(fw_req->type));
diff --git a/include/fsp.h b/include/fsp.h
index ee851ec..7518867 100644
--- a/include/fsp.h
+++ b/include/fsp.h
@@ -581,6 +581,12 @@
#define FSP_RSP_MEM_DYN_DEALLOC 0x00e48500 /* HV->FSP */
/*
+ * Class F2
+ */
+#define FSP_CMD_HBRT_TO_FSP 0x1f20100 /* HV->FSP: HBRT message */
+
+
+/*
* Functions exposed to the rest of skiboot
*/
diff --git a/include/hostservices.h b/include/hostservices.h
index 10cac63..8c54935 100644
--- a/include/hostservices.h
+++ b/include/hostservices.h
@@ -42,5 +42,6 @@ int hservice_send_error_log(uint32_t plid, uint32_t dsize, void *data);
int hservice_wakeup(uint32_t i_core, uint32_t i_mode);
int fsp_occ_reset_status(u64 chipid, s64 status);
int fsp_occ_load_start_status(u64 chipid, s64 status);
+int hservice_send_hbrt_msg(void *data, u64 dsize);
#endif /* __HOSTSERVICES_H */
diff --git a/include/opal-api.h b/include/opal-api.h
index 008ce10..2981b46 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -553,6 +553,7 @@ enum opal_msg_type {
OPAL_MSG_DPO = 5,
OPAL_MSG_PRD = 6,
OPAL_MSG_OCC = 7,
+ OPAL_MSG_PRD2 = 8,
OPAL_MSG_TYPE_MAX,
};
@@ -1094,6 +1095,8 @@ enum opal_prd_msg_type {
OPAL_PRD_MSG_TYPE_FSP_OCC_LOAD_START_STATUS, /* HBRT --> OPAL */
};
+#define OPAL_PRD_MSG_SIZE_MAX (1 << 16)
+
struct opal_prd_msg_header {
uint8_t type;
uint8_t pad[1];
diff --git a/include/prd-fw-msg.h b/include/prd-fw-msg.h
index 333e594..9333a30 100644
--- a/include/prd-fw-msg.h
+++ b/include/prd-fw-msg.h
@@ -44,6 +44,9 @@ struct prd_fw_msg {
__be32 size;
char data[];
} __packed errorlog;
+ struct {
+ char data;
+ } mbox_msg;
};
};
diff --git a/include/psi.h b/include/psi.h
index d51ab94..79555ec 100644
--- a/include/psi.h
+++ b/include/psi.h
@@ -233,6 +233,13 @@
#define PSI_DMA_PLAT_REQ_BUF_SIZE 0x00001000
#define PSI_DMA_PLAT_RESP_BUF 0x03301000
#define PSI_DMA_PLAT_RESP_BUF_SIZE 0x00001000
+/*
+ * Our PRD interface can handle upto 64KB data transfer between
+ * OPAL - opal-prd. Hence adding TCE size as 68KB. If we increase
+ * OPAL - opal-prd message size, then we have to fix this.
+ */
+#define PSI_DMA_HBRT_FSP_MSG 0x03302000
+#define PSI_DMA_HBRT_FSP_MSG_SIZE 0x00011000
/* P8 only mappings */
#define PSI_DMA_TRACE_BASE 0x04000000
diff --git a/include/skiboot.h b/include/skiboot.h
index e828b15..0a7c84a 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -291,6 +291,7 @@ extern void prd_init(void);
extern void prd_register_reserved_memory(void);
extern void prd_fsp_occ_reset(uint32_t proc);
extern void prd_fsp_occ_load_start(u32 proc);
+extern void prd_fw_resp_fsp_response(int status);
/* Flatten device-tree */
extern void *create_dtb(const struct dt_node *root, bool exclusive);