[RFC 0/2] powerpc-utils/devtree: Parse new DRC mem/cpu/dev devtree elems

31 views
Skip to first unread message

Michael Bringmann

<mwb@linux.vnet.ibm.com>
unread,
Dec 1, 2017, 6:19:02 PM12/1/17
to powerpc-utils-devel@googlegroups.com
Several properties in the DRC device tree format are replaced by
more compact representations to allow, for example, for the encoding
of vast amounts of memory, and or reduced duplication of information
in related data structures.

"ibm,drc-info": This property, when present, replaces the following
four properties: "ibm,drc-indexes", "ibm,drc-names", "ibm,drc-types"
and "ibm,drc-power-domains". This property is defined for all
dynamically reconfigurable platform nodes. The "ibm,drc-info" elements
are intended to provide a more compact representation, and reduce some
search overhead.

"ibm,dynamic-memory-v2": This property, when present, replaces the
"ibm,dynamic-memory" property. This property is defined for all
dynamically reconfigurable platform nodes. The new property is
intended to be more compact.

Signed-off-by: Michael Bringmann <m...@linux.vnet.ibm.com>

Michael Bringmann (2):
powerpc-utils/common_ofdt.c: Parse new 'ibm,drc-info' attribute
and use it
powerpc-utils/drslot_chrp_mem.c: Parse new 'ibm,dynamic-memory-v2'
attribute and use it

Michael Bringmann

<mwb@linux.vnet.ibm.com>
unread,
Dec 1, 2017, 6:19:08 PM12/1/17
to powerpc-utils-devel@googlegroups.com
Parse new DRC Info: Define data structures to support parsing
the new "ibm,drc-info" device tree property. Integrate the new
property information into the existing search mechanisms of the
userspace 'drmgr' driver.

Signed-off-by: Michael Bringmann <m...@linux.vnet.ibm.com>
---
src/drmgr/common_ofdt.c | 228 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 199 insertions(+), 29 deletions(-)

diff --git a/src/drmgr/common_ofdt.c b/src/drmgr/common_ofdt.c
index 8c9e224..273e52b 100644
--- a/src/drmgr/common_ofdt.c
+++ b/src/drmgr/common_ofdt.c
@@ -41,6 +41,16 @@ struct drc_prop_grp {
struct of_list_prop drc_domains;
};

+struct drc_info {
+ char *drc_type;
+ char *drc_name_prefix;
+ int drc_index_start;
+ int drc_name_suffix_start;
+ int n_seq_elems;
+ int seq_inc;
+ int drc_power_domain;
+};
+
struct dr_connector *all_drc_lists = NULL;

/**
@@ -187,6 +197,174 @@ build_connectors_list(struct drc_prop_grp *group, int n_entries,
}

/**
+ * drc_info_connectors_v1
+ *
+ * @param full_path
+ * @param ofdt_path
+ * @param list
+ * @returns 0 on success, !0 otherwise
+ */
+static int
+drc_info_connectors_v1(char *full_path, char *ofdt_path,
+ struct dr_connector **list)
+{
+ struct dr_connector *out_list = NULL;
+ struct drc_prop_grp prop_grp;
+ struct of_list_prop *drc_names;
+ int n_drcs;
+ int rc = 0;
+
+ rc = get_drc_prop_grp(full_path, &prop_grp);
+ if (rc) {
+ say(DEBUG,
+ "Could not find DRC property group in path: %s.\n",
+ full_path);
+ goto done;
+ }
+
+ drc_names = &prop_grp.drc_names;
+ n_drcs = drc_names->n_entries;
+
+ out_list = zalloc(n_drcs * sizeof(struct dr_connector));
+ if (out_list == NULL)
+ goto done;
+
+ rc = build_connectors_list(&prop_grp, n_drcs, out_list);
+
+done:
+ if (rc) {
+ free_drc_props(&prop_grp);
+ free(out_list);
+ } else {
+ snprintf(out_list->ofdt_path, DR_PATH_MAX, "%s", ofdt_path);
+ *list = out_list;
+ }
+
+ return rc;
+}
+
+/**
+ * drc_info_connectors_v2
+ *
+ * @param full_path
+ * @param ofdt_path
+ * @param list
+ * @returns 0 on success, !0 otherwise
+ */
+static int
+drc_info_connectors_v2(char *full_path, char *ofdt_path,
+ struct dr_connector **list)
+{
+ struct dr_connector *out_list = NULL;
+ struct drc_info info;
+ char *prop_name = "ibm,drc-info";
+ char *prop_data, *data_ptr;
+ int i, j, k, n_entries, size, connector_size, rc;
+
+ size = get_property_size(full_path, prop_name);
+ prop_data = zalloc(size);
+ if (prop_data == NULL)
+ return -1;
+ rc = get_property(full_path, prop_name, prop_data, size);
+ if (rc) {
+ free(prop_data);
+ return -1;
+ }
+
+ /* Num of DRC-info sets */
+ data_ptr = prop_data;
+ n_entries = be32toh(*data_ptr);
+ data_ptr += 4;
+
+ /* Extract drc-info data */
+ for (j = 0, connector_size = 0; j < n_entries; j++) {
+ info.drc_type = data_ptr;
+ data_ptr += strlen(info.drc_type)+1;
+ info.drc_name_prefix = data_ptr;
+ data_ptr += strlen(info.drc_name_prefix)+1;
+ data_ptr += 4;
+ data_ptr += 4;
+ info.n_seq_elems = be32toh(*data_ptr);
+ data_ptr += 4;
+ data_ptr += 4;
+ data_ptr += 4;
+ if (info.n_seq_elems <= 0)
+ continue;
+ connector_size += info.n_seq_elems;
+ }
+
+ /* Allocate list entry */
+ out_list = zalloc(connector_size * sizeof(struct dr_connector));
+ if (out_list == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ /* Extract drc-info data */
+ for (k = 0, j = 0; j < n_entries; j++) {
+ info.drc_type = data_ptr;
+ data_ptr += strlen(info.drc_type)+1;
+ info.drc_name_prefix = data_ptr;
+ data_ptr += strlen(info.drc_name_prefix)+1;
+
+ info.drc_index_start = be32toh(*data_ptr);
+ data_ptr += 4;
+
+ info.drc_name_suffix_start = be32toh(*data_ptr);
+ data_ptr += 4;
+
+ info.n_seq_elems = be32toh(*data_ptr);
+ data_ptr += 4;
+
+ info.seq_inc = be32toh(*data_ptr);
+ data_ptr += 4;
+
+ info.drc_power_domain = be32toh(*data_ptr);
+ data_ptr += 4;
+
+ /* Build connector list */
+ if (info.n_seq_elems <= 0)
+ continue;
+
+ for (i = 0; i < info.n_seq_elems; i++) {
+ char name[DRC_STR_MAX+1];
+
+ out_list[k+i].index = info.drc_index_start+
+ (i*info.seq_inc);
+ out_list[k+i].powerdomain = info.drc_power_domain;
+
+ sprintf(name, "%s%x", info.drc_name_prefix,
+ info.drc_name_suffix_start+(i*info.seq_inc));
+ strncpy(out_list[k+i].name, name, DRC_STR_MAX);
+
+ strncpy(out_list[k+i].type, info.drc_type, DRC_STR_MAX);
+
+ if (i == (info.n_seq_elems - 1))
+ out_list[k+i].next = NULL;
+ else
+ out_list[k+i].next = &out_list[i+1];
+ }
+
+ k += info.n_seq_elems;
+ }
+
+done:
+ if (prop_data)
+ free(prop_data);
+
+ if (rc) {
+ free(out_list);
+ *list = NULL;
+ } else {
+ snprintf(out_list->ofdt_path, DR_PATH_MAX, "%s", ofdt_path);
+ *list = out_list;
+ }
+
+ return rc;
+}
+
+
+/**
* of_to_full_path
*
* NOTE: Callers of this function are expected to free full_path themselves
@@ -232,11 +410,12 @@ of_to_full_path(const char *of_path)
struct dr_connector *
get_drc_info(const char *of_path)
{
- struct dr_connector *list = NULL;
- struct of_list_prop *drc_names;
- struct drc_prop_grp prop_grp;
+ struct stat sbuf;
+ char fname[DR_PATH_MAX];
+ char ofdt_path[DR_PATH_MAX];
char *full_path = NULL;
- int rc, n_drcs;
+ struct dr_connector *list = NULL;
+ int rc;

for (list = all_drc_lists; list; list = list->all_next) {
if (! strcmp(list->ofdt_path, of_path))
@@ -246,33 +425,24 @@ get_drc_info(const char *of_path)
full_path = of_to_full_path(of_path);
if (full_path == NULL)
return NULL;
-
- rc = get_drc_prop_grp(full_path, &prop_grp);
- if (rc) {
- say(DEBUG, "Could not find DRC property group in path: %s.\n",
- full_path);
- goto done;
- }

- drc_names = &prop_grp.drc_names;
- n_drcs = drc_names->n_entries;
-
- list = zalloc(n_drcs * sizeof(struct dr_connector));
- if (list == NULL)
- goto done;
-
- /* XXX Unchecked rc */
- rc = build_connectors_list(&prop_grp, n_drcs, list);
-
- snprintf(list->ofdt_path, DR_PATH_MAX, "%s", of_path);
-
- list->all_next = all_drc_lists;
- all_drc_lists = list;
+ /* ibm,drc-info vs the old implementation */
+ sprintf(fname, "%s/%s", full_path, "ibm,drc-info");
+ snprintf(ofdt_path, DR_PATH_MAX, "%s", of_path);
+ rc = stat(fname, &sbuf);
+ if (rc)
+ rc = drc_info_connectors_v1(full_path, ofdt_path, &list);
+ else
+ rc = drc_info_connectors_v2(full_path, ofdt_path, &list);

-done:
- free_drc_props(&prop_grp);
- if (full_path)
- free(full_path);
+ if (rc == 0) {
+ list->all_next = all_drc_lists;
+ all_drc_lists = list;
+ } else {
+ if (full_path)
+ free(full_path);
+ list = NULL;
+ }

return list;
}

Nathan Fontenot

<nfont@linux.vnet.ibm.com>
unread,
Dec 4, 2017, 11:58:12 AM12/4/17
to Michael Bringmann, powerpc-utils-devel@googlegroups.com
On 12/01/2017 05:18 PM, Michael Bringmann wrote:
> Parse new DRC Info: Define data structures to support parsing
> the new "ibm,drc-info" device tree property. Integrate the new
> property information into the existing search mechanisms of the
> userspace 'drmgr' driver.
>

A couple of notes. I'm not sure why this RFC is labeled V5 but the other
patches are not. Also, please send out patches so that everything after
patch 0 is a reply to patch 0.

I wonder about your kernel patch set for adding support for the new
ibm,drc-info properties. If this is going out as an RFC, does it work to
perform PCI hotplug? if not how have you been testing the kernel patches?
I know there are places in the drmgr code that put the return value on the
line above the function but we have since switched to using the kernel
coding guidelines since that was done. Please use that style for coding.
Running the kernel checkpatch script on your patches is the easiest way
to check this sort of stuff.
Why the odd +4's here...
> + info.n_seq_elems = be32toh(*data_ptr);
> + data_ptr += 4;
> + data_ptr += 4;
> + data_ptr += 4;

and here? Looks like your skipping over the drc-info elements you do
not need for counting the number of drc entries. If so, a comment
here would be helpful.
Any reason for not writing the name directly to out_list[k+i].name?

-Nathan

Michael Bringmann

<mwb@linux.vnet.ibm.com>
unread,
Dec 5, 2017, 4:00:23 PM12/5/17
to Nathan Fontenot, powerpc-utils-devel@googlegroups.com
See below.

On 12/04/2017 10:47 AM, Nathan Fontenot wrote:
> On 12/01/2017 05:18 PM, Michael Bringmann wrote:
>> Parse new DRC Info: Define data structures to support parsing
>> the new "ibm,drc-info" device tree property. Integrate the new
>> property information into the existing search mechanisms of the
>> userspace 'drmgr' driver.
>>
>
> A couple of notes. I'm not sure why this RFC is labeled V5 but the other
> patches are not. Also, please send out patches so that everything after
> patch 0 is a reply to patch 0.

That was a holdover from the last point at which this RFC was posted as a
patchset. I will use V2... from now on here.

>
> I wonder about your kernel patch set for adding support for the new
> ibm,drc-info properties. If this is going out as an RFC, does it work to
> perform PCI hotplug? if not how have you been testing the kernel patches?

I am calling it an RFC based on our most recent discussion on the topic.
I have been using the patches posted earlier on attached to a local copy
of the package.

We can revise the naming convention.
Okay.
Comments will be added in next patch set submission.
Not that I can think of now. I will change it.
>
> -Nathan

Michael
--
Michael W. Bringmann
Linux Technology Center
IBM Corporation
Tie-Line 363-5196
External: (512) 286-5196
Cell: (512) 466-0650
m...@linux.vnet.ibm.com

Michael Bringmann

<mwb@linux.vnet.ibm.com>
unread,
Dec 12, 2017, 11:59:48 AM12/12/17
to powerpc-utils-devel@googlegroups.com
Several properties in the DRC device tree format are replaced by
more compact representations to allow, for example, for the encoding
of vast amounts of memory, and or reduced duplication of information
in related data structures.

"ibm,drc-info": This property, when present, replaces the following
four properties: "ibm,drc-indexes", "ibm,drc-names", "ibm,drc-types"
and "ibm,drc-power-domains". This property is defined for all
dynamically reconfigurable platform nodes. The "ibm,drc-info" elements
are intended to provide a more compact representation, and reduce some
search overhead.

"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>

Michael Bringmann (2):
powerpc-utils/common_ofdt.c: Parse new 'ibm,drc-info' attribute
and use it
powerpc-utils/drslot_chrp_mem.c: Parse new 'ibm,dynamic-memory-v2'
attribute and use it
---
Changes in V2:
-- Improve some text in the patch descriptions.
-- Change style of patch to match kernel.
-- Add more comments to dr_info_connectors_v2.
-- Simplify a sprintf/strncpy to a sprintf.
-- 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.

Michael Bringmann

<mwb@linux.vnet.ibm.com>
unread,
Dec 12, 2017, 12:00:22 PM12/12/17
to powerpc-utils-devel@googlegroups.com
"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();

Michael Bringmann

<mwb@linux.vnet.ibm.com>
unread,
Dec 12, 2017, 12:00:24 PM12/12/17
to powerpc-utils-devel@googlegroups.com
Subject: [RFC V2 1/2] powerpc-utils/devtree: Parse 'ibm,drc-info' property

From: Michael Bringmann <m...@linux.vnet.ibm.com>

Parse new DRC Info: Define data structures to support parsing
the new "ibm,drc-info" device tree property. Integrate the new
property information into the existing search mechanisms of the
userspace 'drmgr' driver.

Signed-off-by: Michael Bringmann <m...@linux.vnet.ibm.com>
---
Changes in V2:
-- Change style of patch to match kernel.
-- Add more comments to dr_info_connectors_v2.
-- Simplify a sprintf/strncpy to a sprintf.
---
src/drmgr/common_ofdt.c | 226 +++++++++++++++++++++++++++++++++++++++++------
1 file changed, 197 insertions(+), 29 deletions(-)

diff --git a/src/drmgr/common_ofdt.c b/src/drmgr/common_ofdt.c
index 8c9e224..039f0d4 100644
--- a/src/drmgr/common_ofdt.c
+++ b/src/drmgr/common_ofdt.c
@@ -41,6 +41,16 @@ struct drc_prop_grp {
struct of_list_prop drc_domains;
};

+struct drc_info {
+ char *drc_type;
+ char *drc_name_prefix;
+ int drc_index_start;
+ int drc_name_suffix_start;
+ int n_seq_elems;
+ int seq_inc;
+ int drc_power_domain;
+};
+
struct dr_connector *all_drc_lists = NULL;

/**
@@ -187,6 +197,172 @@ build_connectors_list(struct drc_prop_grp *group, int n_entries,
}

/**
+ * drc_info_connectors_v1
+ *
+ * @param full_path
+ * @param ofdt_path
+ * @param list
+ * @returns 0 on success, !0 otherwise
+ */
+static int drc_info_connectors_v1(char *full_path, char *ofdt_path,
+ struct dr_connector **list)
+{
+ struct dr_connector *out_list = NULL;
+ struct drc_prop_grp prop_grp;
+ struct of_list_prop *drc_names;
+ int n_drcs;
+ int rc = 0;
+
+ rc = get_drc_prop_grp(full_path, &prop_grp);
+ if (rc) {
+ say(DEBUG,
+ "Could not find DRC property group in path: %s.\n",
+ full_path);
+ goto done;
+ }
+
+ drc_names = &prop_grp.drc_names;
+ n_drcs = drc_names->n_entries;
+
+ out_list = zalloc(n_drcs * sizeof(struct dr_connector));
+ if (out_list == NULL)
+ goto done;
+
+ rc = build_connectors_list(&prop_grp, n_drcs, out_list);
+
+done:
+ if (rc) {
+ free_drc_props(&prop_grp);
+ free(out_list);
+ } else {
+ snprintf(out_list->ofdt_path, DR_PATH_MAX, "%s", ofdt_path);
+ *list = out_list;
+ }
+
+ return rc;
+}
+
+/**
+ * drc_info_connectors_v2
+ *
+ * @param full_path
+ * @param ofdt_path
+ * @param list
+ * @returns 0 on success, !0 otherwise
+ */
+static int drc_info_connectors_v2(char *full_path, char *ofdt_path,
+ struct dr_connector **list)
+{
+ struct dr_connector *out_list = NULL;
+ struct drc_info info;
+ char *prop_name = "ibm,drc-info";
+ char *prop_data, *data_ptr;
+ int i, j, k, n_entries, size, connector_size, rc;
+
+ size = get_property_size(full_path, prop_name);
+ prop_data = zalloc(size);
+ if (prop_data == NULL)
+ return -1;
+ rc = get_property(full_path, prop_name, prop_data, size);
+ if (rc) {
+ free(prop_data);
+ return -1;
+ }
+
+ /* Num of DRC-info sets */
+ data_ptr = prop_data;
+ n_entries = be32toh(*(uint *)data_ptr);
+ data_ptr += 4;
+
+ /* Extract drc-info data */
+ for (j = 0, connector_size = 0; j < n_entries; j++) {
+ info.drc_type = data_ptr;
+ data_ptr += strlen(info.drc_type)+1;
+ info.drc_name_prefix = data_ptr;
+ data_ptr += strlen(info.drc_name_prefix)+1;
+ data_ptr += 4; /* Skip drc-index-start */
+ data_ptr += 4; /* Skip drc-name-suffix-start */
+ info.n_seq_elems = be32toh(*(uint *)data_ptr);
+ data_ptr += 4; /* Advance over n-seq-elems */
+ data_ptr += 4; /* Skip sequential-increment */
+ data_ptr += 4; /* Skip drc-power-domain */
+ if (info.n_seq_elems <= 0)
+ continue;
+ connector_size += info.n_seq_elems;
+ }
+
+ /* Allocate list entry */
+ out_list = zalloc(connector_size * sizeof(struct dr_connector));
+ if (out_list == NULL) {
+ rc = -1;
+ goto done;
+ }
+
+ /* Extract drc-info data */
+ data_ptr = prop_data;
+ data_ptr += 4;
+ for (k = 0, j = 0; j < n_entries; j++) {
+ info.drc_type = data_ptr;
+ data_ptr += strlen(info.drc_type)+1;
+ info.drc_name_prefix = data_ptr;
+ data_ptr += strlen(info.drc_name_prefix)+1;
+
+ info.drc_index_start = be32toh(*(uint *)data_ptr);
+ data_ptr += 4;
+
+ info.drc_name_suffix_start = be32toh(*(uint *)data_ptr);
+ data_ptr += 4;
+
+ info.n_seq_elems = be32toh(*(uint *)data_ptr);
+ data_ptr += 4;
+
+ info.seq_inc = be32toh(*(uint *)data_ptr);
+ data_ptr += 4;
+
+ info.drc_power_domain = be32toh(*(uint *)data_ptr);
+ data_ptr += 4;
+
+ /* Build connector list */
+ if (info.n_seq_elems <= 0)
+ continue;
+
+ for (i = 0; i < info.n_seq_elems; i++) {
+ out_list[k+i].index = info.drc_index_start+
+ (i*info.seq_inc);
+ out_list[k+i].powerdomain = info.drc_power_domain;
+
+ sprintf(out_list[k+i].name, "%s%d",
+ info.drc_name_prefix,
+ info.drc_name_suffix_start+(i*info.seq_inc));
+
+ strncpy(out_list[k+i].type, info.drc_type, DRC_STR_MAX);
+
+ if (i == (info.n_seq_elems - 1))
+ out_list[k+i].next = NULL;
+ else
+ out_list[k+i].next = &out_list[i+1];
+ }
+
+ k += info.n_seq_elems;
+ }
+
+done:
+ if (prop_data)
+ free(prop_data);
+
+ if (rc) {
+ free(out_list);
+ *list = NULL;
+ } else {
+ snprintf(out_list->ofdt_path, DR_PATH_MAX, "%s", ofdt_path);
+ *list = out_list;
+ }
+
+ return rc;
+}
+
+
+/**
* of_to_full_path
*
* NOTE: Callers of this function are expected to free full_path themselves
@@ -232,11 +408,12 @@ of_to_full_path(const char *of_path)
struct dr_connector *
get_drc_info(const char *of_path)
{
- struct dr_connector *list = NULL;
- struct of_list_prop *drc_names;
- struct drc_prop_grp prop_grp;
+ struct stat sbuf;
+ char fname[DR_PATH_MAX];
+ char ofdt_path[DR_PATH_MAX];
char *full_path = NULL;
- int rc, n_drcs;
+ struct dr_connector *list = NULL;
+ int rc;

for (list = all_drc_lists; list; list = list->all_next) {
if (! strcmp(list->ofdt_path, of_path))
@@ -246,33 +423,24 @@ get_drc_info(const char *of_path)
full_path = of_to_full_path(of_path);
if (full_path == NULL)
return NULL;
-
- rc = get_drc_prop_grp(full_path, &prop_grp);
- if (rc) {
- say(DEBUG, "Could not find DRC property group in path: %s.\n",
- full_path);
- goto done;
- }

- drc_names = &prop_grp.drc_names;
- n_drcs = drc_names->n_entries;
-
- list = zalloc(n_drcs * sizeof(struct dr_connector));
- if (list == NULL)
- goto done;
-
- /* XXX Unchecked rc */
- rc = build_connectors_list(&prop_grp, n_drcs, list);
-
- snprintf(list->ofdt_path, DR_PATH_MAX, "%s", of_path);
-
- list->all_next = all_drc_lists;
- all_drc_lists = list;
+ /* ibm,drc-info vs the old implementation */
+ sprintf(fname, "%s/%s", full_path, "ibm,drc-info");
+ snprintf(ofdt_path, DR_PATH_MAX, "%s", of_path);
+ rc = stat(fname, &sbuf);
+ if (rc)
+ rc = drc_info_connectors_v1(full_path, ofdt_path, &list);
+ else
Reply all
Reply to author
Forward
0 new messages