"ibm,dynamic-memory-v2": This property, when present, replaces the
"ibm,dynamic-memory" property. The "ibm,dynamic-memory[-v2]" property
is defined for all dynamically reconfigurable platform nodes. The
new property representation is intended to be more compact.
Signed-off-by: Michael Bringmann <
m...@linux.vnet.ibm.com>
---
Changes in V2:
-- Change style of patch to match kernel
-- Cleanup coding for 'drmem_version' tracking
-- Remove code that performs memory hotplug in userspace with
drmgr and this new format, and replace it with call to the
kernel mem dlpar interface.
---
src/drmgr/drmem.h | 23 ++++
src/drmgr/drslot_chrp_mem.c | 234 ++++++++++++++++++++++++++++++++++---------
2 files changed, 210 insertions(+), 47 deletions(-)
diff --git a/src/drmgr/drmem.h b/src/drmgr/drmem.h
index 5da6758..0f58beb 100644
--- a/src/drmgr/drmem.h
+++ b/src/drmgr/drmem.h
@@ -20,6 +20,7 @@
#include "drpci.h"
struct lmb_list_head {
+ int mem_version; /* 0=v1; 1=v2 */
struct dr_node *lmbs;
struct dr_node *last;
char *drconf_buf;
@@ -37,12 +38,34 @@ struct drconf_mem {
uint32_t flags;
};
+struct drconf_mem_v2 {
+ uint32_t num_seq_lmbs;
+ uint64_t base_address;
+ uint32_t drc_index;
+ uint32_t assoc_index;
+ uint32_t flags;
+} __packed;
+ /* This is a notional memory structure
+ * for the LMB sets within the
+ * "ibm,dynamic-memory-v2" property.
+ * Unfortunately, it can not be used directly
+ * because of compiler alignment adding pad
+ * bytes in front of the 'uint64_t' element.
+ */
+
#define DRMEM_ASSIGNED 0x00000008
#define DRMEM_DRC_INVALID 0x00000020
#define MEM_PROBE_FILE "/sys/devices/system/memory/probe"
#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 "/proc/device-tree/ibm,dynamic-" \
+ "reconfiguration-memory/" \
+ "ibm,dynamic-memory"
+#define DYNAMIC_RECONFIG_MEM_V2 "/proc/device-tree/ibm,dynamic-" \
+ "reconfiguration-memory/" \
+ "ibm,dynamic-memory-v2"
#define LMB_NORMAL_SORT 0
#define LMB_REVERSE_SORT 1
diff --git a/src/drmgr/drslot_chrp_mem.c b/src/drmgr/drslot_chrp_mem.c
index c59cf8d..f243174 100644
--- a/src/drmgr/drslot_chrp_mem.c
+++ b/src/drmgr/drslot_chrp_mem.c
@@ -32,6 +32,10 @@
#include "ofdt.h"
#include "drmem.h"
+static int drmem_version; /* If v1, then =0, else =1 */
+ #define DR_MEM_V1 0
+ #define DR_MEM_V2 1
+
static int block_sz_bytes = 0;
static char *state_strs[] = {"offline", "online"};
@@ -96,6 +100,9 @@ get_phandle(char *path, uint *phandle)
void
free_lmbs(struct lmb_list_head *lmb_list)
{
+ if (lmb_list == NULL)
+ return;
+
free_node(lmb_list->lmbs);
if (lmb_list->drconf_buf)
@@ -309,47 +316,17 @@ get_mem_node_lmbs(struct lmb_list_head *lmb_list)
/**
* get_dynamic_reconfig_lmbs
* @brief Retrieve lmbs from OF device tree located in the ibm,dynamic-memory
- * property.
*
* @param lmb_list pointer to lmb list head to populate
* @returns 0 on success, !0 on failure
*/
int
-get_dynamic_reconfig_lmbs(struct lmb_list_head *lmb_list)
+get_dynamic_reconfig_lmbs_v1(struct lmb_list_head *lmb_list, uint64_t lmb_sz)
{
struct drconf_mem *drmem;
- uint64_t lmb_sz;
int i, num_entries;
int rc = 0;
- rc = get_property(DYNAMIC_RECONFIG_MEM, "ibm,lmb-size",
- &lmb_sz, sizeof(lmb_sz));
-
- /* convert for LE systems */
- lmb_sz = be64toh(lmb_sz);
-
- if (rc) {
- say(DEBUG, "Could not retrieve drconf LMB size\n");
- return rc;
- }
-
- lmb_list->drconf_buf_sz = get_property_size(DYNAMIC_RECONFIG_MEM,
- "ibm,dynamic-memory");
- 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",
- 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 entries */
num_entries = *(int *)lmb_list->drconf_buf;
@@ -388,7 +365,134 @@ get_dynamic_reconfig_lmbs(struct lmb_list_head *lmb_list)
drmem++; /* trust your compiler */
}
+ return rc;
+}
+
+/*
+ * Read the next memblock set entry from the ibm,dynamic-memory-v2 property
+ * and return the information in the provided drconf_mem_v2 structure.
+ */
+void read_drconf_cell_v2(struct drconf_mem_v2 *drmem, int **cellp)
+{
+ int *cp = (int *)*cellp;
+
+ drmem->num_seq_lmbs = be32toh(*cp++);
+ memcpy(&drmem->base_address, cp, 8);
+ drmem->base_address = be64toh(drmem->base_address);
+ cp += 2;
+
+ drmem->drc_index = be32toh(*cp++);
+ drmem->assoc_index = be32toh(*cp++);
+ drmem->flags = be32toh(*cp++);
+
+ *cellp = cp;
+}
+
+int get_dynamic_reconfig_lmbs_v2(struct lmb_list_head *lmb_list,
+ uint64_t lmb_sz)
+{
+ int i, j, num_entries;
+ int *drmem;
+ int rc = 0;
+
+ /* The first integer of the buffer is the number of entries */
+ drmem = (int *) lmb_list->drconf_buf;
+ num_entries = be32toh(*drmem++);
+
+ /* Followed by the actual entries */
+ for (i = 0; i < num_entries; i++) {
+ struct drconf_mem_v2 drcell;
+
+ read_drconf_cell_v2(&drcell, &drmem);
+
+ for (j = 0; j < drcell.num_seq_lmbs; j++, drcell.drc_index++) {
+ struct dr_node *lmb;
+
+ lmb = lmb_list_add(drcell.drc_index, lmb_list);
+ if (lmb == NULL) {
+ say(DEBUG, "Can't find LMB drc-index of %x\n",
+ drcell.drc_index);
+ continue;
+ }
+
+ sprintf(lmb->ofdt_path, DYNAMIC_RECONFIG_MEM);
+ lmb->lmb_size = lmb_sz;
+ lmb->lmb_address = drcell.base_address;
+ lmb->lmb_aa_index = drcell.assoc_index;
+
+ if (drcell.flags & DRMEM_ASSIGNED) {
+ lmb->is_owned = 1;
+
+ /* find the associated sysfs memory blocks */
+ rc = get_mem_scns(lmb);
+ if (rc)
+ break;
+ }
+
+ lmb_list->lmbs_found++;
+ drcell.base_address += lmb_sz;
+ }
+ }
+
+ return rc;
+}
+
+int
+get_dynamic_reconfig_lmbs(struct lmb_list_head *lmb_list)
+{
+ uint64_t lmb_sz;
+ char *propname;
+ int rc = 0;
+
+ rc = get_property(DYNAMIC_RECONFIG_MEM, "ibm,lmb-size",
+ &lmb_sz, sizeof(lmb_sz));
+ if (rc) {
+ say(DEBUG, "Could not retrieve drconf LMB size\n");
+ return rc;
+ }
+
+ /* Convert for LE systems */
+ lmb_sz = be64toh(lmb_sz);
+
+ switch (drmem_version) {
+ case DR_MEM_V1:
+ propname = "ibm,dynamic-memory";
+ break;
+ case DR_MEM_V2:
+ propname = "ibm,dynamic-memory-v2";
+ break;
+ default:
+ return -1;
+ }
+
+ lmb_list->drconf_buf_sz = get_property_size(DYNAMIC_RECONFIG_MEM,
+ propname);
+ lmb_list->drconf_buf = zalloc(lmb_list->drconf_buf_sz);
+ if (lmb_list->drconf_buf == NULL) {
+ say(DEBUG, "Can't alloc for dynamic reconfigurable memory\n");
+ return -1;
+ }
+
+ rc = get_property(DYNAMIC_RECONFIG_MEM, propname,
+ lmb_list->drconf_buf, lmb_list->drconf_buf_sz);
+ if (rc) {
+ say(DEBUG, "Can't retrieve dynamic reconfig memory property\n");
+ return -1;
+ }
+
+ switch (drmem_version) {
+ case DR_MEM_V1:
+ rc = get_dynamic_reconfig_lmbs_v1(lmb_list, lmb_sz);
+ break;
+ case DR_MEM_V2:
+ rc = get_dynamic_reconfig_lmbs_v2(lmb_list, lmb_sz);
+ break;
+ default:
+ return -1;
+ }
+
say(INFO, "Found %d LMBs currently allocated\n", lmb_list->lmbs_found);
+
return rc;
}
@@ -429,6 +533,27 @@ static void shuffle_lmbs(struct lmb_list_head *lmb_list)
free(shuffled_lmbs);
}
+int
+get_dyn_mem_type(void)
+{
+ int rc;
+ struct stat sbuf;
+
+ rc = stat(DYNAMIC_RECONFIG_MEM_V1, &sbuf);
+ if (!rc)
+ drmem_version = DR_MEM_V1;
+ else {
+ rc = stat(DYNAMIC_RECONFIG_MEM_V2, &sbuf);
+ if (!rc)
+ drmem_version = DR_MEM_V2;
+ else
+ rc = -1;
+ }
+
+ return rc;
+}
+
+
/**
* get_lmbs
* @brief Build a list of all possible lmbs for the system
@@ -442,7 +567,6 @@ get_lmbs(unsigned int sort)
{
struct lmb_list_head *lmb_list = NULL;
struct dr_node *lmb = NULL;
- struct stat sbuf;
char buf[DR_STR_MAX];
int rc = 0;
@@ -471,7 +595,11 @@ get_lmbs(unsigned int sort)
* lmb entries (and their memory sections) as we find their device
* tree entries.
*/
- if (stat(DYNAMIC_RECONFIG_MEM, &sbuf)) {
+ rc = get_dyn_mem_type();
+
+ lmb_list->mem_version = drmem_version;
+
+ if (rc) {
struct dr_connector *drc_list, *drc;
drc_list = get_drc_info(OFDT_BASE);
@@ -587,6 +715,10 @@ static struct dr_node *get_available_lmb(struct dr_node *start_lmb)
return usable_lmb;
}
+/**
+ * update_drconf_node support functions
+ */
+
static void update_drconf_affinity(struct dr_node *lmb,
struct drconf_mem *drmem)
{
@@ -634,9 +766,8 @@ static void update_drconf_affinity(struct dr_node *lmb,
}
free(assoc_prop);
- return;
}
-
+
/**
* update_drconf_node
* @brief update the ibm,dynamic-memory property for added/removed memory
@@ -653,18 +784,17 @@ update_drconf_node(struct dr_node *lmb, struct lmb_list_head *lmb_list,
char *prop_buf;
size_t prop_buf_sz;
char *tmp;
- struct drconf_mem *drmem;
uint phandle;
int i, entries;
int rc;
/* The first int of the buffer is the number of entries */
- entries = *(int *)lmb_list->drconf_buf;
+ entries = be32toh(*(uint32_t *)lmb_list->drconf_buf);
- /* convert for LE systems */
- entries = be32toh(entries);
+ struct drconf_mem *drmem;
- drmem = (struct drconf_mem *)(lmb_list->drconf_buf + sizeof(entries));
+ drmem = (struct drconf_mem *)(lmb_list->drconf_buf +
+ sizeof(entries));
for (i = 0; i < entries; i++) {
@@ -685,13 +815,15 @@ update_drconf_node(struct dr_node *lmb, struct lmb_list_head *lmb_list,
/* Now create the buffer we pass to the kernel to have this
* property updated. This buffer has the format
- * "update_property <phandle> ibm,dynamic-memory <prop_len> <prop> \
- * [strlen("remove") | strlen("add")] <drc_index> "
*
- * The simple collapsing of all strings, spaces, and ints makes this
- * a length of 61 + the size of the drconf property, round the
- * calculation to 128 + <property_size> to ensure the buffer is
- * always big enough.
+ * update_property <phandle> ibm,dynamic-memory
+ * <prop_len> <prop> [strlen("remove") | strlen("add")]
+ * <drc_index>
+ *
+ * The simple collapsing of all strings, spaces, and ints
+ * makes this a length of 61 + the size of the drconf property,
+ * round the calculation to 128 + <property_size> to ensure the
+ * buffer is always big enough.
*/
prop_buf_sz = 128 + lmb_list->drconf_buf_sz;
prop_buf = zalloc(prop_buf_sz);
@@ -1368,6 +1500,11 @@ int drslot_chrp_mem(void)
return -1;
}
+ if (get_dyn_mem_type()) {
+ say(ERROR, "DLPAR memory ops can't find needed properties.");
+ return -1;
+ }
+
/* The recursive nature of the routines that add/remove lmbs
* require that the quantity be non-zero.
*/
@@ -1377,7 +1514,10 @@ int drslot_chrp_mem(void)
if (kernel_dlpar_exists()) {
rc = do_mem_kernel_dlpar();
} else {
- if (usr_action == ADD)
+ if (drmem_version == DR_MEM_V2) {
+ say(ERROR, "DLPAR mem hotplug ops require sysfs I/F.");
+ return -1;
+ } else if (usr_action == ADD)
rc = mem_add();
else if (usr_action == REMOVE)
rc = mem_remove();