|
@@ -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) {
|