diff mbox series

[V10,04/21] core/pldm: Add PLDM responder support

Message ID 20230829092338.75785-5-clombard@linux.ibm.com
State Accepted
Headers show
Series Implement MCTP and PLDM features | expand

Commit Message

Christophe Lombard Aug. 29, 2023, 9:23 a.m. UTC
PLDM defines data representations and commands that abstract the platform
management hardware.

A PLDM Terminus (or responder) is defined as the point of communication
termination for PLDM messages and the PLDM functions associated with those
messages.
A PLDM terminus is not required to process more than one request at a time
(that is, it can be "single threaded" and does not have to accept and act
on new requests until it has finished responding to any previous request).

Some PLDM control and discovery requests (PLDM_TYPE = PLDM_BASE) are
mandatory a PLDM terminus has to answer.

These following mandatory PLDM command codes for PLDM messaging control
and discovery will be defined in next patches.
    GetTID          0x02
    GetPLDMVersion  0x03
    GetPLDMTypes    0x04
    GetPLDMCommands 0x05

Reviewed-by: Abhishek Singh Tomar <abhishek@linux.ibm.com>
Signed-off-by: Christophe Lombard <clombard@linux.ibm.com>
---
 core/pldm/Makefile.inc     |   2 +-
 core/pldm/pldm-mctp.c      |  15 +++-
 core/pldm/pldm-responder.c | 154 +++++++++++++++++++++++++++++++++++++
 core/pldm/pldm.h           |   6 ++
 4 files changed, 175 insertions(+), 2 deletions(-)
 create mode 100644 core/pldm/pldm-responder.c
diff mbox series

Patch

diff --git a/core/pldm/Makefile.inc b/core/pldm/Makefile.inc
index ae45bb8ba..9aa72a77c 100644
--- a/core/pldm/Makefile.inc
+++ b/core/pldm/Makefile.inc
@@ -7,7 +7,7 @@  SUBDIRS += $(PLDM_DIR)
 CPPFLAGS += -I$(SRC)/pldm/include/
 CPPFLAGS += -I$(SRC)/pldm/include/libpldm/oem/ibm/
 
-PLDM_OBJS = pldm-mctp.o
+PLDM_OBJS = pldm-mctp.o pldm-responder.o
 
 PLDM = $(PLDM_DIR)/built-in.a
 $(PLDM): $(PLDM_OBJS:%=$(PLDM_DIR)/%)
diff --git a/core/pldm/pldm-mctp.c b/core/pldm/pldm-mctp.c
index fb675849d..0e6a7e37a 100644
--- a/core/pldm/pldm-mctp.c
+++ b/core/pldm/pldm-mctp.c
@@ -53,6 +53,17 @@  int pldm_mctp_message_rx(uint8_t eid, bool tag_owner, uint8_t msg_tag,
 		goto out;
 	}
 
+	switch (rx->hdrinf.msg_type) {
+	case PLDM_REQUEST:
+		rc = pldm_responder_handle_request(rx);
+	break;
+	default:
+		prlog(PR_ERR, "%s: message not supported (msg type: 0%x)\n",
+			      __func__, rx->hdrinf.msg_type);
+		rc = OPAL_PARAMETER;
+	break;
+	}
+
 out:
 	free(rx);
 	return rc;
@@ -60,14 +71,16 @@  out:
 
 int pldm_mctp_init(void)
 {
-	int nbr_elt = 1, rc = OPAL_SUCCESS;
+	int nbr_elt = 2, rc = OPAL_SUCCESS;
 
 	int (*pldm_config[])(void) = {
 		ast_mctp_init,		/* MCTP Binding */
+		pldm_responder_init,	/* Register mandatory commands we'll respond to */
 	};
 
 	const char *pldm_config_error[] = {
 		"Failed to bind MCTP",
+		"Failed to register mandatory commands",
 	};
 
 	prlog(PR_NOTICE, "%s - Getting PLDM data\n", __func__);
diff --git a/core/pldm/pldm-responder.c b/core/pldm/pldm-responder.c
new file mode 100644
index 000000000..74376f177
--- /dev/null
+++ b/core/pldm/pldm-responder.c
@@ -0,0 +1,154 @@ 
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+// Copyright 2022 IBM Corp.
+
+#define pr_fmt(fmt) "PLDM: " fmt
+
+#include <bitmap.h>
+#include <cpu.h>
+#include <opal.h>
+#include <stdio.h>
+#include <string.h>
+#include <libpldm/utils.h>
+#include "pldm.h"
+
+struct pldm_type {
+	const char *name;
+	int pldm_type_id;
+	ver32_t version;
+
+	struct list_head commands;
+	struct list_node link;
+};
+
+struct pldm_cmd {
+	const char *name;
+	int pldm_cmd_id;
+
+	int (*handler)(const struct pldm_rx_data *rx);
+
+	struct list_node link; /* link in the msg type's command list */
+};
+
+/*
+ * Send a response with just a completion code and no payload
+ */
+static int cc_resp(const struct pldm_rx_data *rx, uint8_t type,
+			uint8_t command, uint8_t cc)
+{
+	size_t data_size = PLDM_MSG_SIZE(uint8_t);
+	struct pldm_tx_data *tx;
+	int rc;
+
+	/* Encode the cc response */
+	tx = zalloc(sizeof(struct pldm_tx_data) + data_size);
+	if (!tx)
+		return OPAL_NO_MEM;
+	tx->data_size = data_size;
+	tx->tag_owner = true;
+	tx->msg_tag = rx->msg_tag;
+
+	encode_cc_only_resp(rx->hdrinf.instance,
+			    type,
+			    command,
+			    cc,
+			    (struct pldm_msg *)tx->data);
+
+	rc = pldm_mctp_message_tx(tx);
+	if (rc) {
+		prlog(PR_ERR, "Failed to send response message containing only cc, "
+			      "rc = %d, cc = %d\n", rc, cc);
+		free(tx);
+		return OPAL_HARDWARE;
+	}
+
+	free(tx);
+	return OPAL_SUCCESS;
+}
+
+/*
+ * PLDM Type / Command wrangling.
+ */
+LIST_HEAD(pldm_type_list);
+
+static const struct pldm_type *find_type(int type_id)
+{
+	struct pldm_type *iter;
+
+	list_for_each(&pldm_type_list, iter, link) {
+		if (iter->pldm_type_id == type_id)
+			return iter;
+	}
+
+	return NULL;
+}
+
+static const struct pldm_cmd *find_cmd(const struct pldm_type *type, int cmd)
+{
+	struct pldm_cmd *iter;
+
+	list_for_each(&type->commands, iter, link)
+		if (iter->pldm_cmd_id == cmd)
+			return iter;
+
+	return NULL;
+}
+
+static void add_type(struct pldm_type *new_type)
+{
+	assert(new_type->pldm_type_id < 32); /* limited by GetPLDMTypes */
+	assert(!find_type(new_type->pldm_type_id));
+
+	list_head_init(&new_type->commands);
+	list_add_tail(&pldm_type_list, &new_type->link);
+
+	prlog(PR_DEBUG, "Registered type %s (%d)\n",
+	      new_type->name, new_type->pldm_type_id);
+}
+
+/*
+ * PLDM Base commands support
+ */
+static struct pldm_type pldm_base_type = {
+	.name = "base",
+	.pldm_type_id = PLDM_BASE,
+	.version = { 0xF1, 0xF0, 0xF0, 0x00 },
+};
+
+int pldm_responder_handle_request(struct pldm_rx_data *rx)
+{
+	const struct pldm_type *type;
+	const struct pldm_cmd *cmd;
+
+	prlog(PR_INFO, "Receive PLDM request from BMC, type: 0x%x, command: 0x%x\n",
+			rx->hdrinf.pldm_type, rx->hdrinf.command);
+
+	type = find_type(rx->hdrinf.pldm_type);
+	if (!type) {
+		prlog(PR_ERR, "Type not supported, type: 0x%x\n",
+			      rx->hdrinf.pldm_type);
+		cc_resp(rx, rx->hdrinf.pldm_type,
+			rx->hdrinf.command,
+			PLDM_ERROR_INVALID_PLDM_TYPE);
+		return OPAL_UNSUPPORTED;
+	}
+
+	cmd = find_cmd(type, rx->hdrinf.command);
+	if (!cmd) {
+		prlog(PR_ERR, "Command not supported, type: 0x%x, command: 0x%x\n",
+			      rx->hdrinf.pldm_type, rx->hdrinf.command);
+		cc_resp(rx, rx->hdrinf.pldm_type,
+			rx->hdrinf.command,
+			PLDM_ERROR_UNSUPPORTED_PLDM_CMD);
+		return OPAL_UNSUPPORTED;
+	}
+
+	return cmd->handler(rx);
+}
+
+int pldm_responder_init(void)
+{
+	/* Register mandatory commands we'll respond to - DSP0240 */
+	add_type(&pldm_base_type);
+
+	return OPAL_SUCCESS;
+}
diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h
index bd32cf853..d6eda42f5 100644
--- a/core/pldm/pldm.h
+++ b/core/pldm/pldm.h
@@ -9,6 +9,8 @@ 
 #include <base.h>
 #include <pldm.h>
 
+#define PLDM_MSG_SIZE(x) (sizeof(struct pldm_msg_hdr) + sizeof(x))
+
 struct pldm_tx_data {
 	/* Contains an message header and payload of an MCTP packet.
 	 * Size of data[]
@@ -41,4 +43,8 @@  int pldm_mctp_message_tx(struct pldm_tx_data *tx);
 int pldm_mctp_message_rx(uint8_t eid, bool tag_owner, uint8_t msg_tag,
 			 const uint8_t *buf, int len);
 
+/* Responder support */
+int pldm_responder_handle_request(struct pldm_rx_data *rx);
+int pldm_responder_init(void);
+
 #endif /* __COREPLDM_H__ */