powerpc/pseries: Make dlpar_configure_connector parent node aware
authorTyrel Datwyler <tyreld@linux.vnet.ibm.com>
Thu, 15 Aug 2013 05:23:50 +0000 (22:23 -0700)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 27 Aug 2013 04:45:14 +0000 (14:45 +1000)
Currently the device nodes created in the device subtree returned by a call to
dlpar_configure_connector are all named in the root node. This is because the
the node name in the work area returned by ibm,configure-connector rtas call
only contains the node name and not the entire node path. Passing the parent
node where the new subtree will be created to dlpar_configure_connector allows
the correct node path to be prefixed in the full_name field.

Signed-off-by: Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
Acked-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/platforms/pseries/dlpar.c
arch/powerpc/platforms/pseries/mobility.c
arch/powerpc/platforms/pseries/pseries.h

index c85523355779292244d51ac03942a2bf0cca2c9a..4ea667d2b0f38a77eb8ff8a3988885d277f0e1b8 100644 (file)
@@ -63,21 +63,24 @@ static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
        return prop;
 }
 
-static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa)
+static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
+                                              const char *path)
 {
        struct device_node *dn;
        char *name;
 
+       /* If parent node path is "/" advance path to NULL terminator to
+        * prevent double leading slashs in full_name.
+        */
+       if (!path[1])
+               path++;
+
        dn = kzalloc(sizeof(*dn), GFP_KERNEL);
        if (!dn)
                return NULL;
 
-       /* The configure connector reported name does not contain a
-        * preceding '/', so we allocate a buffer large enough to
-        * prepend this to the full_name.
-        */
        name = (char *)ccwa + ccwa->name_offset;
-       dn->full_name = kasprintf(GFP_KERNEL, "/%s", name);
+       dn->full_name = kasprintf(GFP_KERNEL, "%s/%s", path, name);
        if (!dn->full_name) {
                kfree(dn);
                return NULL;
@@ -123,7 +126,8 @@ void dlpar_free_cc_nodes(struct device_node *dn)
 #define CALL_AGAIN     -2
 #define ERR_CFG_USE     -9003
 
-struct device_node *dlpar_configure_connector(u32 drc_index)
+struct device_node *dlpar_configure_connector(u32 drc_index,
+                                             struct device_node *parent)
 {
        struct device_node *dn;
        struct device_node *first_dn = NULL;
@@ -132,6 +136,7 @@ struct device_node *dlpar_configure_connector(u32 drc_index)
        struct property *last_property = NULL;
        struct cc_workarea *ccwa;
        char *data_buf;
+       const char *parent_path = parent->full_name;
        int cc_token;
        int rc = -1;
 
@@ -165,7 +170,7 @@ struct device_node *dlpar_configure_connector(u32 drc_index)
                        break;
 
                case NEXT_SIBLING:
-                       dn = dlpar_parse_cc_node(ccwa);
+                       dn = dlpar_parse_cc_node(ccwa, parent_path);
                        if (!dn)
                                goto cc_error;
 
@@ -175,13 +180,17 @@ struct device_node *dlpar_configure_connector(u32 drc_index)
                        break;
 
                case NEXT_CHILD:
-                       dn = dlpar_parse_cc_node(ccwa);
+                       if (first_dn)
+                               parent_path = last_dn->full_name;
+
+                       dn = dlpar_parse_cc_node(ccwa, parent_path);
                        if (!dn)
                                goto cc_error;
 
-                       if (!first_dn)
+                       if (!first_dn) {
+                               dn->parent = parent;
                                first_dn = dn;
-                       else {
+                       else {
                                dn->parent = last_dn;
                                if (last_dn)
                                        last_dn->child = dn;
@@ -205,6 +214,7 @@ struct device_node *dlpar_configure_connector(u32 drc_index)
 
                case PREV_PARENT:
                        last_dn = last_dn->parent;
+                       parent_path = last_dn->parent->full_name;
                        break;
 
                case CALL_AGAIN:
@@ -383,9 +393,8 @@ out:
 
 static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
 {
-       struct device_node *dn;
+       struct device_node *dn, *parent;
        unsigned long drc_index;
-       char *cpu_name;
        int rc;
 
        cpu_hotplug_driver_lock();
@@ -395,25 +404,19 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
                goto out;
        }
 
-       dn = dlpar_configure_connector(drc_index);
-       if (!dn) {
-               rc = -EINVAL;
+       parent = of_find_node_by_path("/cpus");
+       if (!parent) {
+               rc = -ENODEV;
                goto out;
        }
 
-       /* configure-connector reports cpus as living in the base
-        * directory of the device tree.  CPUs actually live in the
-        * cpus directory so we need to fixup the full_name.
-        */
-       cpu_name = kasprintf(GFP_KERNEL, "/cpus%s", dn->full_name);
-       if (!cpu_name) {
-               dlpar_free_cc_nodes(dn);
-               rc = -ENOMEM;
+       dn = dlpar_configure_connector(drc_index, parent);
+       if (!dn) {
+               rc = -EINVAL;
                goto out;
        }
 
-       kfree(dn->full_name);
-       dn->full_name = cpu_name;
+       of_node_put(parent);
 
        rc = dlpar_acquire_drc(drc_index);
        if (rc) {
index ed5426f5b03cf176866c6df638057ec4e8347182..ff102e27a3dca104bb87bb1453bb80961fca478b 100644 (file)
@@ -216,17 +216,14 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index)
        struct device_node *parent_dn;
        int rc;
 
-       dn = dlpar_configure_connector(drc_index);
-       if (!dn)
+       parent_dn = of_find_node_by_phandle(parent_phandle);
+       if (!parent_dn)
                return -ENOENT;
 
-       parent_dn = of_find_node_by_phandle(parent_phandle);
-       if (!parent_dn) {
-               dlpar_free_cc_nodes(dn);
+       dn = dlpar_configure_connector(drc_index, parent_dn);
+       if (!dn)
                return -ENOENT;
-       }
 
-       dn->parent = parent_dn;
        rc = dlpar_attach_node(dn);
        if (rc)
                dlpar_free_cc_nodes(dn);
index d1b07e645302aaa5037f2344610a23d14f6d4409..99219530ea4aaad0da768b72d84a4caa1f96fcb0 100644 (file)
@@ -56,7 +56,7 @@ extern void hvc_vio_init_early(void);
 /* Dynamic logical Partitioning/Mobility */
 extern void dlpar_free_cc_nodes(struct device_node *);
 extern void dlpar_free_cc_property(struct property *);
-extern struct device_node *dlpar_configure_connector(u32);
+extern struct device_node *dlpar_configure_connector(u32, struct device_node *);
 extern int dlpar_attach_node(struct device_node *);
 extern int dlpar_detach_node(struct device_node *);