From 3ce17a36d10bc09a49af9d56ceadad09708b46f1 Mon Sep 17 00:00:00 2001
From: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Date: Thu, 19 Jul 2018 23:12:40 -0500
Subject: [PATCH] lsslot: Add ibm,dynamic-memory-v2 parsing capability

In order to support reporting memory LMB information the lsslot
command needs to know how to parse the ibm,dynamic-memory-v2
property. This patch adds this support to the shared
drslot_chrp_mem.c file.

In order to prevent the drmgr command from parsing this v2 property
a new flag is introduce, is_lsslot_cmd. The reason for this is that
we do not support memory DLPAR for ibm,dynamic-memory-v2 from
userspace.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
---
 src/drmgr/dr.h              |   2 +
 src/drmgr/drmem.h           |   9 ++++
 src/drmgr/drmgr.c           |   2 +
 src/drmgr/drslot_chrp_mem.c | 119 +++++++++++++++++++++++++++++++++++++-------
 src/drmgr/lsslot.c          |   2 +
 5 files changed, 117 insertions(+), 17 deletions(-)

diff --git a/src/drmgr/dr.h b/src/drmgr/dr.h
index d5295808afb5..68728cbb7517 100644
--- a/src/drmgr/dr.h
+++ b/src/drmgr/dr.h
@@ -32,6 +32,8 @@
 extern int output_level;
 extern int log_fd;
 
+extern int is_lsslot_cmd;
+
 /* Error Exit Codes */
 #define RC_IN_USE		1
 #define RC_NONEXISTENT 		3
diff --git a/src/drmgr/drmem.h b/src/drmgr/drmem.h
index 70f9bc5f754c..04df6eaae316 100644
--- a/src/drmgr/drmem.h
+++ b/src/drmgr/drmem.h
@@ -37,6 +37,14 @@ struct drconf_mem {
 	uint32_t	flags;
 };
 
+struct drconf_mem_v2 {
+	uint32_t	seq_lmbs;
+	uint64_t	base_addr;
+	uint32_t	drc_index;
+	uint32_t	aa_index;
+	uint32_t	flags;
+} __attribute__((packed));
+
 #define DRMEM_ASSIGNED		0x00000008
 #define DRMEM_DRC_INVALID	0x00000020
 
@@ -44,6 +52,7 @@ struct drconf_mem {
 #define MEM_BLOCK_SIZE_BYTES	"/sys/devices/system/memory/block_size_bytes"
 #define DYNAMIC_RECONFIG_MEM	"/proc/device-tree/ibm,dynamic-reconfiguration-memory"
 #define DYNAMIC_RECONFIG_MEM_V1	DYNAMIC_RECONFIG_MEM "/ibm,dynamic-memory"
+#define DYNAMIC_RECONFIG_MEM_V2	DYNAMIC_RECONFIG_MEM "/ibm,dynamic-memory-v2"
 
 #define LMB_NORMAL_SORT		0
 #define LMB_REVERSE_SORT	1
diff --git a/src/drmgr/drmgr.c b/src/drmgr/drmgr.c
index 09e842720acf..0f207ccf187d 100644
--- a/src/drmgr/drmgr.c
+++ b/src/drmgr/drmgr.c
@@ -38,6 +38,8 @@ int output_level = 1; /* default to lowest output level */
 int log_fd = 0;
 int action_cnt = 0;
 
+int is_lsslot_cmd = 0;
+
 static int handle_prrn_event = 0;
 static int display_usage = 0;
 
diff --git a/src/drmgr/drslot_chrp_mem.c b/src/drmgr/drslot_chrp_mem.c
index dda6e9fb19ba..5dfbdf442ad5 100644
--- a/src/drmgr/drslot_chrp_mem.c
+++ b/src/drmgr/drslot_chrp_mem.c
@@ -306,6 +306,38 @@ get_mem_node_lmbs(struct lmb_list_head *lmb_list)
 	return rc;
 }
 
+int add_lmb(struct lmb_list_head *lmb_list, uint32_t drc_index,
+	    uint64_t address, uint64_t lmb_sz, uint32_t aa_index,
+	    uint32_t flags)
+{
+	struct dr_node *lmb;
+
+	lmb = lmb_list_add(drc_index, lmb_list);
+	if (lmb == NULL) {
+		say(DEBUG, "Could not find LMB with drc-index of %x\n",
+		    drc_index);
+		return -1;
+	}
+
+	sprintf(lmb->ofdt_path, DYNAMIC_RECONFIG_MEM);
+	lmb->lmb_size = lmb_sz;
+	lmb->lmb_address = address;
+	lmb->lmb_aa_index = aa_index;
+
+	if (flags & DRMEM_ASSIGNED) {
+		int rc;
+
+		lmb->is_owned = 1;
+
+		/* find the associated sysfs memory blocks */
+		rc = get_mem_scns(lmb);
+		if (rc)
+			return -1;
+	}
+
+	lmb_list->lmbs_found++;
+	return 0;
+}
 /**
  * get_dynamic_reconfig_lmbs_v1
  * @brief Retrieve lmbs from OF device tree located in the ibm,dynamic-memory
@@ -349,31 +381,81 @@ get_dynamic_reconfig_lmbs_v1(uint64_t lmb_sz, struct lmb_list_head *lmb_list)
 	drmem = (struct drconf_mem *)
 				(lmb_list->drconf_buf + sizeof(num_entries));
 	for (i = 0; i < num_entries; i++) {
-		struct dr_node *lmb;
-
-		lmb = lmb_list_add(be32toh(drmem->drc_index), lmb_list);
-		if (lmb == NULL) {
-			say(DEBUG, "Could not find LMB with drc-index of %x\n",
-			    drmem->drc_index);
-			rc = -1;
+		rc = add_lmb(lmb_list, be32toh(drmem->drc_index),
+			     be64toh(drmem->address), lmb_sz,
+			     be32toh(drmem->assoc_index),
+			     be32toh(drmem->flags));
+		if (rc)
 			break;
-		}
 
-		sprintf(lmb->ofdt_path, DYNAMIC_RECONFIG_MEM);
-		lmb->lmb_size = lmb_sz;
-		lmb->lmb_address = be64toh(drmem->address);
-		lmb->lmb_aa_index = be32toh(drmem->assoc_index);
+		drmem++; /* trust your compiler */
+	}
+
+	return rc;
+}
+
+/**
+ * get_dynamic_reconfig_lmbs_v2
+ * @brief Retrieve the LMBs from the ibm,dynamic-memory-v2 property
+ *
+ * @param lmb_sz LMB size
+ * @param lmb_list pointer to lmb_list head to populate
+ * @returns 0 on success, !0 on failure.
+ */
+int get_dynamic_reconfig_lmbs_v2(uint64_t lmb_sz,
+				 struct lmb_list_head *lmb_list)
+{
+	struct drconf_mem_v2 *drmem;
+	uint32_t lmb_sets;
+	int i, rc = 0;
+
+	lmb_list->drconf_buf_sz = get_property_size(DYNAMIC_RECONFIG_MEM,
+						   "ibm,dynamic-memory-v2");
+	lmb_list->drconf_buf = zalloc(lmb_list->drconf_buf_sz);
+	if (lmb_list->drconf_buf == NULL) {
+		say(DEBUG, "Could not allocate buffer to get dynamic "
+		    "reconfigurable memory\n");
+		return -1;
+	}
+
+	rc = get_property(DYNAMIC_RECONFIG_MEM, "ibm,dynamic-memory-v2",
+			  lmb_list->drconf_buf, lmb_list->drconf_buf_sz);
+	if (rc) {
+		say(DEBUG, "Could not retrieve dynamic reconfigurable memory "
+		    "property\n");
+		return -1;
+	}
+
+	/* The first integer of the buffer is the number of lmb sets */
+	lmb_sets = *(int *)lmb_list->drconf_buf;
+	lmb_sets = be32toh(lmb_sets);
+
+	/* Followed by the actual entries */
+	drmem = (struct drconf_mem_v2 *)
+				(lmb_list->drconf_buf + sizeof(lmb_sets));
 
-		if (be32toh(drmem->flags) & DRMEM_ASSIGNED) {
-			lmb->is_owned = 1;
+	for (i = 0; i < lmb_sets; i++) {
+		uint32_t drc_index, seq_lmbs;
+		uint64_t address;
+		int j;
 
-			/* find the associated sysfs memory blocks */
-			rc = get_mem_scns(lmb);
+		address = be64toh(drmem->base_addr);
+		drc_index = be32toh(drmem->drc_index);
+		seq_lmbs = be32toh(drmem->seq_lmbs);
+
+		for (j = 0; j < seq_lmbs; j++) {
+			uint32_t aa_index = be32toh(drmem->aa_index);
+			uint32_t flags = be32toh(drmem->flags);
+
+			rc = add_lmb(lmb_list, drc_index, address,
+				     lmb_sz, aa_index, flags);
 			if (rc)
 				break;
+
+			drc_index++;
+			address += lmb_sz;
 		}
 
-		lmb_list->lmbs_found++;
 		drmem++; /* trust your compiler */
 	}
 
@@ -408,6 +490,9 @@ get_dynamic_reconfig_lmbs(struct lmb_list_head *lmb_list)
 
 	if (stat(DYNAMIC_RECONFIG_MEM_V1, &sbuf) == 0) {
 		rc = get_dynamic_reconfig_lmbs_v1(lmb_sz, lmb_list);
+	} else if (is_lsslot_cmd &&
+		   stat(DYNAMIC_RECONFIG_MEM_V2, &sbuf) == 0) {
+		rc = get_dynamic_reconfig_lmbs_v2(lmb_sz, lmb_list);
 	} else {
 		say(ERROR, "No dynamic reconfiguration LMBs found\n");
 		return -1;
diff --git a/src/drmgr/lsslot.c b/src/drmgr/lsslot.c
index d297af9af251..6828478e4c19 100644
--- a/src/drmgr/lsslot.c
+++ b/src/drmgr/lsslot.c
@@ -35,6 +35,8 @@
 int output_level = 0;
 int log_fd = 0;
 
+int is_lsslot_cmd = 1;
+
 extern int lsslot_chrp_cpu(void);
 
 /**
-- 
2.13.7

