aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lombard <clombard@linux.ibm.com>2023-08-29 11:23:27 +0200
committerReza Arbab <arbab@linux.ibm.com>2023-09-12 14:22:11 -0500
commitce16acd4390aba8661b6a9f41d025c25895a8371 (patch)
treef2548286e3fca2a0690582b319a851a527e6f635
parent819a4145a85f05c465899d5777d8f94dc3619052 (diff)
downloadskiboot-ce16acd4390aba8661b6a9f41d025c25895a8371.zip
skiboot-ce16acd4390aba8661b6a9f41d025c25895a8371.tar.gz
skiboot-ce16acd4390aba8661b6a9f41d025c25895a8371.tar.bz2
core/pldm: PLDM for Platform Monitoring and Control Specification
This specification defines the functions and data structures used for discovering, describing, initializing, and accessing sensors and effecters within the management controllers and management devices of a platform management subsystem using PLDM messaging. A PDR (Platform Descriptor Record) is a set of data that is used to provide semantic information about sensors, effecters, monitored or controller entities, and functions and services within a PLDM implementation. PDRs are mostly used to support PLDM monitoring and control and platform events. The PDRs for a PLDM subsystem are collected into a single, central PDR Repository. A central repository provides a single place from which PDR information can be retrieved. The GetPDR command is used to retrieve individual PDRs from a PDR Repository. The record is identified by the PDR recordHandle value that is passed in the request. The patch dump all the PDRs within a PDR Repository. Reviewed-by: Abhishek Singh Tomar <abhishek@linux.ibm.com> Signed-off-by: Christophe Lombard <clombard@linux.ibm.com> Signed-off-by: Reza Arbab <arbab@linux.ibm.com>
-rw-r--r--core/pldm/Makefile.inc1
-rw-r--r--core/pldm/pldm-base-requests.c76
-rw-r--r--core/pldm/pldm-mctp.c8
-rw-r--r--core/pldm/pldm-platform-requests.c309
-rw-r--r--core/pldm/pldm.h9
5 files changed, 402 insertions, 1 deletions
diff --git a/core/pldm/Makefile.inc b/core/pldm/Makefile.inc
index f2328a4..933b0c6 100644
--- a/core/pldm/Makefile.inc
+++ b/core/pldm/Makefile.inc
@@ -8,6 +8,7 @@ CPPFLAGS += -I$(SRC)/pldm/include/
CPPFLAGS += -I$(SRC)/pldm/include/libpldm/oem/ibm/
PLDM_OBJS = pldm-mctp.o pldm-responder.o pldm-requester.o
+PLDM_OBJS += pldm-base-requests.o pldm-platform-requests.o
PLDM = $(PLDM_DIR)/built-in.a
$(PLDM): $(PLDM_OBJS:%=$(PLDM_DIR)/%)
diff --git a/core/pldm/pldm-base-requests.c b/core/pldm/pldm-base-requests.c
new file mode 100644
index 0000000..d898427
--- /dev/null
+++ b/core/pldm/pldm-base-requests.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+// Copyright 2022 IBM Corp.
+
+#define pr_fmt(fmt) "PLDM: " fmt
+
+#include <cpu.h>
+#include <opal.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <libpldm/base.h>
+#include "pldm.h"
+
+static uint8_t bmc_tid = -1;
+
+uint8_t pldm_base_get_bmc_tid(void)
+{
+ return bmc_tid;
+}
+
+/*
+ * Create a PLDM request message for GetTID.
+ */
+int pldm_base_get_tid_req(void)
+{
+ size_t data_size = PLDM_MSG_SIZE(0); /* the command doesn't have a message payload */
+ size_t response_len, payload_len;
+ struct pldm_tx_data *tx = NULL;
+ void *response_msg;
+ int rc;
+
+ struct pldm_get_tid_resp response;
+
+ /* Encode the get tid request */
+ tx = zalloc(sizeof(struct pldm_tx_data) + data_size);
+ if (!tx)
+ return OPAL_NO_MEM;
+ tx->data_size = data_size;
+
+ rc = encode_get_tid_req(DEFAULT_INSTANCE_ID,
+ (struct pldm_msg *)tx->data);
+ if (rc != PLDM_SUCCESS) {
+ prlog(PR_ERR, "Encode GetTID Error, rc: %d\n", rc);
+ free(tx);
+ return OPAL_PARAMETER;
+ }
+
+ /* Send and get the response message bytes */
+ rc = pldm_requester_queue_and_wait(tx, &response_msg, &response_len);
+ if (rc) {
+ prlog(PR_ERR, "Communication Error, req: GetTID, rc: %d\n", rc);
+ free(tx);
+ return rc;
+ }
+
+ /* Decode the message */
+ payload_len = response_len - sizeof(struct pldm_msg_hdr);
+
+ rc = decode_get_tid_resp(response_msg, payload_len,
+ &response.completion_code,
+ &response.tid);
+ if ((rc != PLDM_SUCCESS) || (response.completion_code != PLDM_SUCCESS)) {
+ prlog(PR_ERR, "Decode GetTID Error, rc: %d, cc: %d\n",
+ rc, response.completion_code);
+ free(tx);
+ free(response_msg);
+ return OPAL_PARAMETER;
+ }
+
+ prlog(PR_INFO, "BMC's TID is %d\n", response.tid);
+ bmc_tid = response.tid;
+ free(tx);
+ free(response_msg);
+
+ return OPAL_SUCCESS;
+}
diff --git a/core/pldm/pldm-mctp.c b/core/pldm/pldm-mctp.c
index 569fe25..a07d950 100644
--- a/core/pldm/pldm-mctp.c
+++ b/core/pldm/pldm-mctp.c
@@ -74,18 +74,22 @@ out:
int pldm_mctp_init(void)
{
- int nbr_elt = 3, rc = OPAL_SUCCESS;
+ int nbr_elt = 5, rc = OPAL_SUCCESS;
int (*pldm_config[])(void) = {
ast_mctp_init, /* MCTP Binding */
pldm_responder_init, /* Register mandatory commands we'll respond to */
pldm_requester_init, /* Requester implementation */
+ pldm_base_get_tid_req, /* Get BMC tid */
+ pldm_platform_init, /* Get PDRs data */
};
const char *pldm_config_error[] = {
"Failed to bind MCTP",
"Failed to register mandatory commands",
"Failed to configure requister",
+ "Failed to retrieve BMC Tid",
+ "Failed to retrieve Data Records",
};
prlog(PR_NOTICE, "%s - Getting PLDM data\n", __func__);
@@ -105,5 +109,7 @@ out:
void pldm_mctp_exit(void)
{
+ pldm_platform_exit();
+
ast_mctp_exit();
}
diff --git a/core/pldm/pldm-platform-requests.c b/core/pldm/pldm-platform-requests.c
new file mode 100644
index 0000000..6c01918
--- /dev/null
+++ b/core/pldm/pldm-platform-requests.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+// Copyright 2022 IBM Corp.
+
+#define pr_fmt(fmt) "PLDM: " fmt
+
+#include <cpu.h>
+#include <opal.h>
+#include <stdio.h>
+#include <string.h>
+#include <timebase.h>
+#include <inttypes.h>
+#include <libpldm/entity.h>
+#include <libpldm/pdr.h>
+#include <libpldm/state_set.h>
+#include <libpldm/platform.h>
+#include "pldm.h"
+
+#define NO_MORE_PDR_HANDLES 0
+
+static pldm_pdr *pdrs_repo;
+static bool pdr_ready;
+
+struct pldm_pdrs {
+ struct pldm_tx_data *tx;
+ uint32_t record_hndl;
+ bool done;
+ int rc;
+};
+
+struct pldm_pdrs *pdrs;
+
+static void pdr_init_complete(bool success)
+{
+ /* Read not successful, error out and free the buffer */
+ if (!success) {
+ pdr_ready = false;
+
+ if (pdrs_repo)
+ pldm_pdr_destroy(pdrs_repo);
+ return;
+ }
+
+ /* Mark ready */
+ pdr_ready = true;
+}
+
+struct get_pdr_response {
+ uint8_t completion_code;
+ uint32_t next_record_hndl;
+ uint32_t next_data_transfer_hndl;
+ uint8_t transfer_flag;
+ uint16_t resp_cnt;
+ uint8_t *record_data;
+ size_t record_data_length;
+ uint8_t transfer_crc;
+};
+
+static int encode_and_queue_get_pdr_req(struct pldm_pdrs *pdrs);
+
+static void get_pdr_req_complete(struct pldm_rx_data *rx,
+ void *data)
+{
+ struct pldm_pdrs *pdrs = (struct pldm_pdrs *)data;
+ uint32_t record_hndl = pdrs->record_hndl;
+ struct get_pdr_response response;
+ size_t payload_len;
+ int rc, i;
+
+ prlog(PR_DEBUG, "%s - record_hndl: %d\n", __func__, record_hndl);
+
+ if (rx == NULL) {
+ pdrs->rc = OPAL_PARAMETER;
+ pdrs->done = true;
+ }
+
+ /* Decode the message twice; the first time, the payload buffer
+ * will be null so that the decoder will simply tell us how big
+ * the buffer should be. Then we create a suitable payload
+ * buffer and call the decoder again, this time with the real
+ * buffer so that it can fill it with data from the message.
+ *
+ * transfer_crc is not used in case of PLDM_START_AND_END.
+ */
+ payload_len = rx->msg_len - sizeof(struct pldm_msg_hdr);
+ response.record_data_length = 0;
+ response.record_data = NULL;
+
+ for (i = 0; i < 2; i++) {
+ rc = decode_get_pdr_resp(
+ rx->msg, payload_len,
+ &response.completion_code,
+ &response.next_record_hndl,
+ &response.next_data_transfer_hndl,
+ &response.transfer_flag,
+ &response.resp_cnt,
+ response.record_data,
+ response.record_data_length,
+ &response.transfer_crc);
+
+ if (rc != PLDM_SUCCESS || response.completion_code != PLDM_SUCCESS) {
+ /* Message decoding failed */
+ prlog(PR_ERR, "Decode GetPDRResp Error (rc: %d, cc: %d)\n",
+ rc, response.completion_code);
+
+ /* BMC is not ready, try again. This behavior can be
+ * encountered when the BMC reboots and the host is
+ * still operational.
+ * The host receives a GET VERSION request indicating
+ * that we must rehcrage the pdrs.
+ */
+ if (response.completion_code == PLDM_ERROR_NOT_READY) {
+ time_wait_ms(500);
+ encode_and_queue_get_pdr_req(pdrs);
+ return;
+ }
+
+ pdrs->rc = OPAL_PARAMETER;
+ pdrs->done = true;
+ return;
+ }
+
+ if (response.record_data == NULL) {
+ response.record_data_length = response.resp_cnt;
+ response.record_data = zalloc(response.resp_cnt);
+ if (!response.record_data) {
+ prlog(PR_ERR, "failed to allocate record data (size: 0x%lx)\n", response.record_data_length);
+ pdrs->rc = OPAL_NO_MEM;
+ pdrs->done = true;
+ return;
+ }
+ }
+ }
+
+ /* we do not support multipart transfer */
+ if (response.transfer_flag != PLDM_START_AND_END)
+ prlog(PR_ERR, "Transfert GetPDRResp not complete, transfer_flag: %d\n",
+ response.transfer_flag);
+
+ prlog(PR_DEBUG, "%s - record_hndl: %d, next_record_hndl: %d, resp_cnt: %d\n",
+ __func__, record_hndl,
+ response.next_record_hndl,
+ response.resp_cnt);
+
+ /* Add a PDR record to a PDR repository.
+ * Use HOST_TID as terminus handle
+ */
+ pldm_pdr_add(pdrs_repo,
+ response.record_data,
+ response.resp_cnt,
+ record_hndl,
+ false,
+ HOST_TID);
+
+ free(response.record_data);
+
+ if (response.next_record_hndl != NO_MORE_PDR_HANDLES) {
+ pdrs->record_hndl = response.next_record_hndl;
+ encode_and_queue_get_pdr_req(pdrs);
+ } else {
+ /* We have to indicate the end of the initialization when we
+ * reload the pdrs in background
+ */
+ pdr_init_complete(true);
+ pdrs->done = true;
+ pdrs->rc = OPAL_SUCCESS;
+ prlog(PR_DEBUG, "%s - done\n", __func__);
+ }
+}
+
+/*
+ * Send/receive a PLDM GetPDR stateEffecter request message
+ * Get platform descriptor records.
+ *
+ * pldmtool platform GetPDR -t stateEffecter
+ * ...
+ * {
+ * "nextRecordHandle": 138,
+ * "responseCount": 30,
+ * "recordHandle": 137,
+ * "PDRHeaderVersion": 1,
+ * "PDRType": "State Effecter PDR",
+ * "recordChangeNumber": 0,
+ * "dataLength": 20,
+ * "PLDMTerminusHandle": 1,
+ * "effecterID": 43,
+ * "entityType": "[Physical] System chassis (main enclosure)",
+ * ...
+ * "Off-Soft Graceful(9)"
+ * }
+ * ...
+ */
+static int encode_and_queue_get_pdr_req(struct pldm_pdrs *pdrs)
+{
+ uint32_t record_hndl = pdrs->record_hndl;
+ int rc;
+
+ struct pldm_get_pdr_req pdr_req = {
+ .record_handle = record_hndl, /* record change number (0 for first request) */
+ .data_transfer_handle = 0, /* (0 if transfer op is FIRSTPART) */
+ .transfer_op_flag = PLDM_GET_FIRSTPART, /* transfer op flag */
+ .request_count = SHRT_MAX, /* Don't limit the size of the PDR */
+ .record_change_number = 0 /* record change number (0 for first request) */
+ };
+
+ prlog(PR_DEBUG, "%s - record_hndl: %d\n", __func__, record_hndl);
+
+ /* Encode the get_PDR request */
+ rc = encode_get_pdr_req(DEFAULT_INSTANCE_ID,
+ pdr_req.record_handle,
+ pdr_req.data_transfer_handle,
+ pdr_req.transfer_op_flag,
+ pdr_req.request_count,
+ pdr_req.record_change_number,
+ (struct pldm_msg *)pdrs->tx->data,
+ PLDM_GET_PDR_REQ_BYTES);
+ if (rc != PLDM_SUCCESS) {
+ prlog(PR_ERR, "Encode GetPDRReq Error, rc: %d\n", rc);
+ pdrs->done = true;
+ pdrs->rc = OPAL_PARAMETER;
+ return OPAL_PARAMETER;
+ }
+
+ /* Queue the first getpdr request */
+ rc = pldm_requester_queue(pdrs->tx, get_pdr_req_complete, pdrs);
+ if (rc) {
+ prlog(PR_ERR, "Communication Error, req: GetPDRReq, rc: %d\n", rc);
+ pdrs->done = true;
+ pdrs->rc = OPAL_PARAMETER;
+ }
+
+ return rc;
+}
+
+static int pldm_platform_load_pdrs(void)
+{
+ /* destroy current repo and mark repo not ready */
+ pdr_init_complete(false);
+
+ /* make a new PDR repository */
+ pdrs_repo = pldm_pdr_init();
+
+ /* collect all PDrs into a PDR Repository */
+ pdrs->record_hndl = 0;
+ pdrs->done = false;
+ return encode_and_queue_get_pdr_req(pdrs);
+}
+
+static int pdrs_init(void)
+{
+ int rc;
+
+ rc = pldm_platform_load_pdrs();
+ if (rc)
+ return rc;
+
+ /* wait for the end of pdrs received */
+ for (;;) {
+ if (pdrs->done)
+ break;
+
+ time_wait_ms(5);
+ }
+ return pdrs->rc;
+}
+
+int pldm_platform_init(void)
+{
+ size_t data_size = PLDM_MSG_SIZE(struct pldm_get_pdr_req);
+ int rc;
+
+ pdrs = zalloc(sizeof(struct pldm_pdrs));
+ if (!pdrs) {
+ prlog(PR_ERR, "failed to allocate pdrs\n");
+ return OPAL_NO_MEM;
+ }
+
+ pdrs->tx = zalloc(sizeof(struct pldm_tx_data) + data_size);
+ if (!pdrs->tx)
+ return OPAL_NO_MEM;
+ pdrs->tx->data_size = data_size;
+
+ /* retrieve all PDRs */
+ rc = pdrs_init();
+ if (rc)
+ goto err;
+
+ pdr_init_complete(true);
+ prlog(PR_DEBUG, "%s - done\n", __func__);
+
+ return OPAL_SUCCESS;
+
+err:
+ prlog(PR_ERR, "%s - failed to initialize pdrs, rc: %d\n", __func__, rc);
+ pdr_init_complete(false);
+ free(pdrs->tx);
+ free(pdrs);
+ return rc;
+}
+
+void pldm_platform_exit(void)
+{
+ if (pdr_ready)
+ pldm_pdr_destroy(pdrs_repo);
+
+ if (pdrs) {
+ free(pdrs->tx);
+ free(pdrs);
+ }
+}
diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h
index 7c7da9f..fd79597 100644
--- a/core/pldm/pldm.h
+++ b/core/pldm/pldm.h
@@ -11,6 +11,9 @@
#define PLDM_MSG_SIZE(x) (sizeof(struct pldm_msg_hdr) + sizeof(x))
+/* For all of the encode functions just pass in a default ID (0x00) */
+#define DEFAULT_INSTANCE_ID 0
+
struct pldm_tx_data {
/* Contains an message header and payload of an MCTP packet.
* Size of data[]
@@ -48,6 +51,12 @@ int pldm_responder_handle_request(struct pldm_rx_data *rx);
int pldm_responder_init(void);
/* Requester support */
+uint8_t pldm_base_get_bmc_tid(void);
+int pldm_base_get_tid_req(void);
+
+int pldm_platform_init(void);
+void pldm_platform_exit(void);
+
int pldm_requester_handle_response(struct pldm_rx_data *rx);
int pldm_requester_queue(struct pldm_tx_data *tx,
void (*complete)(struct pldm_rx_data *rx, void *data),