[SPARC64]: Fix handling of multiple vdc-port nodes.

The "id" property in vdc-port nodes are not unique, they
are all zero.  Therefore assign ID's using the parent's
"cfg-handle" property which will be unique.

Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index 302ba5e..13a79fe 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -231,6 +231,25 @@
 	mutex_unlock(&mdesc_mutex);
 }
 
+static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
+{
+	const u64 *id;
+	u64 a;
+
+	id = NULL;
+	mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+		u64 target;
+
+		target = mdesc_arc_target(hp, a);
+		id = mdesc_get_property(hp, target,
+					"cfg-handle", NULL);
+		if (id)
+			break;
+	}
+
+	return id;
+}
+
 /* Run 'func' on nodes which are in A but not in B.  */
 static void invoke_on_missing(const char *name,
 			      struct mdesc_handle *a,
@@ -240,13 +259,42 @@
 	u64 node;
 
 	mdesc_for_each_node_by_name(a, node, name) {
-		const u64 *id = mdesc_get_property(a, node, "id", NULL);
-		int found = 0;
+		int found = 0, is_vdc_port = 0;
+		const char *name_prop;
+		const u64 *id;
 		u64 fnode;
 
+		name_prop = mdesc_get_property(a, node, "name", NULL);
+		if (name_prop && !strcmp(name_prop, "vdc-port")) {
+			is_vdc_port = 1;
+			id = parent_cfg_handle(a, node);
+		} else
+			id = mdesc_get_property(a, node, "id", NULL);
+
+		if (!id) {
+			printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
+			       (name_prop ? name_prop : name));
+			continue;
+		}
+
 		mdesc_for_each_node_by_name(b, fnode, name) {
-			const u64 *fid = mdesc_get_property(b, fnode,
-							    "id", NULL);
+			const u64 *fid;
+
+			if (is_vdc_port) {
+				name_prop = mdesc_get_property(b, fnode,
+							       "name", NULL);
+				if (!name_prop ||
+				    strcmp(name_prop, "vdc-port"))
+					continue;
+				fid = parent_cfg_handle(b, fnode);
+				if (!fid) {
+					printk(KERN_ERR "MD: Cannot find ID "
+					       "for vdc-port node.\n");
+					continue;
+				}
+			} else
+				fid = mdesc_get_property(b, fnode,
+							 "id", NULL);
 
 			if (*id == *fid) {
 				found = 1;
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 7e65b5a..9ae1f61 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -221,6 +221,27 @@
 		return NULL;
 	}
 
+	if (!strcmp(type, "vdc-port")) {
+		u64 a;
+
+		id = NULL;
+		mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+			u64 target;
+
+			target = mdesc_arc_target(hp, a);
+			id = mdesc_get_property(hp, target,
+						"cfg-handle", NULL);
+			if (id)
+				break;
+		}
+		if (!id) {
+			printk(KERN_ERR "VIO: vdc-prot lacks parent "
+			       "cfg-handle.\n");
+			return NULL;
+		}
+	} else
+		id = mdesc_get_property(hp, mp, "id", NULL);
+
 	bus_id_name = type;
 	if (!strcmp(type, "domain-services-port"))
 		bus_id_name = "ds";
@@ -260,13 +281,15 @@
 
 	vio_fill_channel_info(hp, mp, vdev);
 
-	id = mdesc_get_property(hp, mp, "id", NULL);
-	if (!id)
+	if (!id) {
 		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
 			 bus_id_name);
-	else
+		vdev->dev_no = ~(u64)0;
+	} else {
 		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
 			 bus_id_name, *id);
+		vdev->dev_no = *id;
+	}
 
 	vdev->dev.parent = parent;
 	vdev->dev.bus = &vio_bus_type;