[Skiboot] [PATCH v7 14/22] fadump: Add OPAL API to register for fadump

Vasant Hegde hegdevasant at linux.vnet.ibm.com
Sat Apr 13 19:15:40 AEST 2019


This patch adds new API for fadump.
  int64_t opal_fadump_manage(uint64_t cmd, void *data, uint64_t dsize)

  cmd : 0x01 -> Register for fadump
        0x02 -> Unregister fadump
	0x03 -> Invalidate existing dump

  data : For cmd = 0x01, data contains payload section reservation details
         (uses fadump structure format to send data).
         For other cmd values, data will be NULL.
  dsize: Size of data

Return values:
  OPAL_SUCCESS   : Operation success
  OPAL_PARAMETER : Payload passed invalid data
  OPAL_RESOURCE  : Ran out of MDST or MDDT table size
  OPAL_PERMISSION: Already registered
  OPAL_HARDWARE  : Fadump not supported

Signed-off-by: Vasant Hegde <hegdevasant at linux.vnet.ibm.com>
---
 core/opal-dump.c   | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/opal-api.h |  13 +++-
 2 files changed, 206 insertions(+), 1 deletion(-)

diff --git a/core/opal-dump.c b/core/opal-dump.c
index 8e4014335..6400cbdb1 100644
--- a/core/opal-dump.c
+++ b/core/opal-dump.c
@@ -37,6 +37,197 @@ static struct spira_ntuple *ntuple_mdst;
 static struct spira_ntuple *ntuple_mddt;
 static struct spira_ntuple *ntuple_mdrt;
 
+/* Clear MDRT memory */
+static inline void opal_dump_invalidate(void)
+{
+	struct mdrt_table *mdrt = (void *)(MDRT_TABLE_BASE);
+
+	memset(mdrt, 0, MDRT_TABLE_SIZE);
+	/* Reset MDRT count */
+	ntuple_mdrt->act_cnt =
+		cpu_to_be16(MDRT_TABLE_SIZE / sizeof(struct mdrt_table));
+	ntuple_mdrt->alloc_cnt =
+		cpu_to_be16(MDRT_TABLE_SIZE / sizeof(struct mdrt_table));
+}
+
+static void opal_dump_unregister(void)
+{
+	int i, j;
+	struct mdst_table *mdst, *tmp_mdst;
+	struct mddt_table *mddt, *tmp_mddt;
+
+	mdst = (void *)(MDST_TABLE_BASE);
+	for (i = 0; i < ntuple_mdst->act_cnt; ) {
+		if (mdst->dump_type != DUMP_TYPE_FADUMP ||
+		    mdst->data_region < FADUMP_REGION_HOST_START) {
+			mdst++;
+			i++;
+			continue;
+		}
+
+		tmp_mdst = mdst;
+		memset(tmp_mdst, 0, sizeof(struct mdst_table));
+		for (j = i; j < ntuple_mdst->act_cnt - 1; j++) {
+			memcpy((void *)tmp_mdst,
+			       (void *)(tmp_mdst + 1), sizeof(struct mdst_table));
+			tmp_mdst++;
+			memset(tmp_mdst, 0, sizeof(struct mdst_table));
+		}
+		ntuple_mdst->act_cnt--;
+	}
+
+	mddt = (void *)(MDDT_TABLE_BASE);
+	for (i = 0; i < ntuple_mddt->act_cnt; ) {
+		if (mddt->data_region < FADUMP_REGION_HOST_START) {
+			mddt++;
+			i++;
+			continue;
+		}
+
+		tmp_mddt = mddt;
+		memset(tmp_mddt, 0, sizeof(struct mddt_table));
+		for (j = i; j < ntuple_mddt->act_cnt - 1; j++) {
+			memcpy((void *)tmp_mddt,
+			       (void *)(tmp_mddt + 1), sizeof(struct mddt_table));
+			tmp_mddt++;
+			memset(tmp_mddt, 0, sizeof(struct mddt_table));
+		}
+		ntuple_mddt->act_cnt--;
+	}
+}
+
+static int opal_dump_register(void *data, uint64_t dsize)
+{
+	int i, sec_cnt, max_mdst_entry, max_mddt_entry;
+	struct fadump_section *section;
+	struct fadump *fadump = (void *)data;
+	struct mdst_table *mdst = (void *)(MDST_TABLE_BASE);
+	struct mddt_table *mddt = (void *)(MDDT_TABLE_BASE);
+
+	if (dsize < sizeof(struct fadump)) {
+		prlog(PR_DEBUG, "data size [0x%llx] < minimum size [0x%lx]\n",
+		      dsize, sizeof(struct fadump));
+		return OPAL_PARAMETER;
+	}
+
+	sec_cnt = be16_to_cpu(fadump->section_count);
+	if (sec_cnt <= 0) {
+		prlog(PR_DEBUG, "Invalid section count = 0x%x\n", sec_cnt);
+		return OPAL_PARAMETER;
+	}
+
+	max_mdst_entry = MDST_TABLE_SIZE / sizeof(struct mdst_table);
+	if (ntuple_mdst->act_cnt >= (max_mdst_entry + sec_cnt)) {
+		prlog(PR_DEBUG, "MDST table is full\n");
+		return OPAL_RESOURCE;
+	}
+
+	max_mddt_entry = MDDT_TABLE_SIZE / sizeof(struct mddt_table);
+	if (ntuple_mddt->act_cnt >= (max_mddt_entry + sec_cnt)) {
+		prlog(PR_DEBUG, "MDDT table is full\n");
+		return OPAL_RESOURCE;
+	}
+
+	/* Already registered ? */
+	for (i = 0; i < ntuple_mdst->act_cnt; i++) {
+		if (mdst->dump_type == DUMP_TYPE_FADUMP &&
+		    mdst->data_region >= FADUMP_REGION_HOST_START) {
+			prlog(PR_DEBUG, "Already registered\n");
+			return OPAL_PERMISSION;
+		}
+		mdst++;
+	}
+
+	mdst = (struct mdst_table *)(MDST_TABLE_BASE +
+				     ntuple_mdst->act_cnt * sizeof(struct mdst_table));
+	mddt = (struct mddt_table *)(MDDT_TABLE_BASE +
+				     ntuple_mddt->act_cnt * sizeof(struct mddt_table));
+	for (i = 0; i < sec_cnt; i++) {
+		section = &(fadump->section[i]);
+
+		if (section->source_type < FADUMP_REGION_HOST_START) {
+			prlog(PR_DEBUG, "Invalid source type [0x%x]\n",
+			      section->source_type);
+			goto clr_entry;
+		}
+
+		if (!opal_addr_valid((void *)section->source_addr)) {
+			prlog(PR_DEBUG, "Invalid source address [0x%llx]\n",
+			      section->source_addr);
+			goto clr_entry;
+		}
+
+		if (!opal_addr_valid((void *)section->dest_addr)) {
+			prlog(PR_DEBUG, "Invalid dest address [0x%llx]\n",
+			      section->dest_addr);
+			goto clr_entry;
+		}
+
+		if (section->source_size <= 0) {
+			prlog(PR_DEBUG, "Invalid source size [0x%llx]\n",
+			      section->source_size);
+			goto clr_entry;
+		}
+
+		if (section->dest_size <= 0) {
+			prlog(PR_DEBUG, "Invalid source size [0x%llx]\n",
+			      section->dest_size);
+			goto clr_entry;
+		}
+
+		mdst->dump_type = DUMP_TYPE_FADUMP;
+		mdst->data_region = section->source_type;
+		mdst->addr = section->source_addr | HRMOR_BIT;
+		mdst->size = section->source_size;
+		mdst++;
+		ntuple_mdst->act_cnt++;
+
+		mddt->data_region = section->source_type;
+		mddt->addr = section->dest_addr | HRMOR_BIT;
+		mddt->size = section->dest_size;
+		mddt++;
+		ntuple_mddt->act_cnt++;
+
+		prlog(PR_NOTICE, "Registered new entry : src - 0x%llx, "
+		      "dst - 0x%llx, size - 0x%llx\n", section->source_addr,
+		      section->dest_addr, section->source_size);
+	}
+
+	return OPAL_SUCCESS;
+
+clr_entry:
+	opal_dump_unregister();
+	return OPAL_PARAMETER;
+}
+
+static int64_t opal_fadump_manage(uint64_t cmd, void *data, uint64_t dsize)
+{
+	int rc = OPAL_SUCCESS;
+
+	prlog(PR_TRACE, "opal_fadump_manage : cmd - 0x%llx\n", cmd);
+
+	switch (cmd) {
+	case OPAL_FADUMP_REGISTER:
+		rc = opal_dump_register(data, dsize);
+		if (rc == OPAL_SUCCESS)
+			prlog(PR_NOTICE, "Payload registered for fadump\n");
+		break;
+	case OPAL_FADUMP_UNREGISTER:
+		opal_dump_unregister();
+		prlog(PR_NOTICE, "Payload unregistered for fadump\n");
+		break;
+	case OPAL_FADUMP_INVALIDATE:
+		opal_dump_invalidate();
+		prlog(PR_NOTICE, "Payload invalidated fadump\n");
+		break;
+	default:
+		prlog(PR_ERR, "Unsupported command : 0x%llx\n", cmd);
+		rc = OPAL_PARAMETER;
+		break;
+	}
+
+	return rc;
+}
 
 /* Reserve OPAL dump destination memory */
 static void add_dump_reserve_node(struct dt_node *dump_node)
@@ -171,4 +362,7 @@ void opal_dump_init(void)
 	ntuple_mdrt = &(spirah.ntuples.mdump_res);
 
 	adjust_opal_dump_size(dump_node);
+
+	/* OPAL interface */
+	opal_register(OPAL_FADUMP_MANAGE, opal_fadump_manage, 3);
 }
diff --git a/include/opal-api.h b/include/opal-api.h
index e783540e1..702e70841 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -229,7 +229,8 @@
 #define OPAL_XIVE_GET_VP_STATE			170 /* Get NVT state */
 #define OPAL_NPU_RESERVED1			171  /* LPC Allocate */
 #define OPAL_NPU_RESERVED2			172  /* LPC Release */
-#define OPAL_LAST				172
+#define OPAL_FADUMP_MANAGE			173
+#define OPAL_LAST				173
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
@@ -1350,6 +1351,16 @@ struct fadump {
 	struct	fadump_section section[];
 };
 
+/*
+ * Command option argument for fadump manage API (OPAL_FADUMP_MANAGE)
+ *  - for registration payload should pass memory reservation details
+ *  - Unregister option removes all entries from payload
+ *  - Invalidate option invalidatates existing fadump
+ * */
+#define OPAL_FADUMP_REGISTER	0x01
+#define OPAL_FADUMP_UNREGISTER	0x02
+#define OPAL_FADUMP_INVALIDATE	0x03
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __OPAL_API_H */
-- 
2.14.3



More information about the Skiboot mailing list