diff mbox series

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

Message ID 20180703061727.8789-14-hegdevasant@linux.vnet.ibm.com
State Superseded
Headers show
Series MPIPL support | expand

Commit Message

Vasant Hegde July 3, 2018, 6:17 a.m. UTC
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  | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/opal-api.h |  13 +++-
 2 files changed, 193 insertions(+), 1 deletion(-)

Comments

Stewart Smith Aug. 7, 2018, 7:45 a.m. UTC | #1
Vasant Hegde <hegdevasant@linux.vnet.ibm.com> writes:
> 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

I'm thinking that the existing OPAL_(UN)REGISTER_DUMP_REGION calls could
be adequate here?

Even in the case where the kernel doesn't know anything about the new
dump infrastructure, if we passed something back via the OPAL_DUMP_READ
interface that we use on FSP systems today, we'd have a net gain in
functionality without any kernel (or userspace) changes. Or am I missing
something?
Vasant Hegde Aug. 16, 2018, 4:50 a.m. UTC | #2
On 08/07/2018 01:15 PM, Stewart Smith wrote:
> Vasant Hegde <hegdevasant@linux.vnet.ibm.com> writes:
>> 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
> 
> I'm thinking that the existing OPAL_(UN)REGISTER_DUMP_REGION calls could
> be adequate here?

Unfortunately OPAL_(UN)REGISTER_DUMP_REGION is not sufficient. In case of current
FSP SYSDUMP, kernel just passes memory to be captured. OPAL takes care of TCE 
mapping.

But in case of MPIPL, we want kernel to reserve memory for kernel dump and pass 
that detail
to OPAL.

> 
> Even in the case where the kernel doesn't know anything about the new
> dump infrastructure, if we passed something back via the OPAL_DUMP_READ
> interface that we use on FSP systems today, we'd have a net gain in
> functionality without any kernel (or userspace) changes. Or am I missing
> something?

In case of SYSDUMP, we want kernel to allocate memory, pass detail to OPAL. OPAL 
does TCE
mapping and gets actual dump from FSP.

But in case of MPIPL, flow is different. Here during first boot (before crash) 
we populate
MDST  and MDDT table inside HDAT/SPIRAH structure with details of source and 
destination
memory. During crash boot (second boot) Hostboot will take care of moving memory 
content.
By the time we boot OPAL we already have memory content in destination memory. 
Kernel
will use these details to generate vmcore and opal core.

One thing we can consider is exporting OPAL dump via sysfs (similar to the way 
we export
raw HDAT content). So that even if kernel doesn't know anything about MPIPL we 
can still retrieve OPAL dump. I will add that support once this patchset is merged.

-Vasant
diff mbox series

Patch

diff --git a/core/opal-mpipl.c b/core/opal-mpipl.c
index 9e95cdbae..455ecbd2a 100644
--- a/core/opal-mpipl.c
+++ b/core/opal-mpipl.c
@@ -37,6 +37,184 @@  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));
+}
+
+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 +347,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 e35b621b2..a099b0250 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -224,7 +224,8 @@ 
 #define OPAL_PCI_SET_PBCQ_TUNNEL_BAR		165
 #define OPAL_HANDLE_HMI2			166
 #define OPAL_NX_COPROC_INIT			167
-#define OPAL_LAST				167
+#define OPAL_FADUMP_MANAGE			168
+#define OPAL_LAST				168
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
@@ -1342,6 +1343,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 */