[v5,13/18] fadump: Add OPAL API to register for fadump

Message ID 20180816085721.11703-14-hegdevasant@linux.vnet.ibm.com
State New
Headers show
Series
  • MPIPL support
Related show

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success master/apply_patch Successfully applied

Commit Message

Vasant Hegde Aug. 16, 2018, 8:57 a.m.
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, MDDT table size
  OPAL_PERMISSION: Already registered
  OPAL_HARDWARE  : Fadump not supported

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

Patch

diff --git a/core/opal-mpipl.c b/core/opal-mpipl.c
index 2a4d13a52..1779bc56f 100644
--- a/core/opal-mpipl.c
+++ b/core/opal-mpipl.c
@@ -37,6 +37,186 @@  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_fadump_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_fadump_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_fadump_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 is less than minimum size "
+		      "[dsize = 0x%llx]\n", dsize);
+		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 "
+			      "[addr = 0x%llx]\n", section->source_addr);
+			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++;
+
+		if (!opal_addr_valid((void *)section->dest_addr)) {
+			prlog(PR_DEBUG, "Invalid destination address "
+			      "[addr = 0x%llx]\n", section->dest_addr);
+			goto clr_entry;
+		}
+
+		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_fadump_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_fadump_register(data, dsize);
+		if (rc == OPAL_SUCCESS)
+			prlog(PR_NOTICE, "Payload registered for MPIPL\n");
+		break;
+	case OPAL_FADUMP_UNREGISTER:
+		opal_fadump_unregister();
+		prlog(PR_NOTICE, "Payload unregistered for MPIPL\n");
+		break;
+	case OPAL_FADUMP_INVALIDATE:
+		opal_fadump_invalidate();
+		prlog(PR_NOTICE, "Payload invalidated dump\n");
+		break;
+	default:
+		prlog(PR_DEBUG, "Unsupported command : 0x%llx\n", cmd);
+		rc = OPAL_PARAMETER;
+		break;
+	}
+
+	return rc;
+}
 
 /* Reserve OPAL dump destination memory */
 static void add_fadump_reserve_node(struct dt_node *dump_node)
@@ -169,4 +349,7 @@  void opal_fadump_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 91c787ce9..2fd283bd2 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -226,7 +226,8 @@ 
 #define OPAL_NX_COPROC_INIT			167
 #define OPAL_NPU_SET_RELAXED_ORDER		168
 #define OPAL_NPU_GET_RELAXED_ORDER		169
-#define OPAL_LAST				169
+#define OPAL_FADUMP_MANAGE			170
+#define OPAL_LAST				170
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
@@ -1344,6 +1345,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 */