summary refs log tree commit diff
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/mdesc.c2
-rw-r--r--arch/sparc/kernel/vio.c120
2 files changed, 60 insertions, 62 deletions
diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c
index f795ee015738..e4b4e790bf89 100644
--- a/arch/sparc/kernel/mdesc.c
+++ b/arch/sparc/kernel/mdesc.c
@@ -574,6 +574,7 @@ u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name,
 
 	return hp_node;
 }
+EXPORT_SYMBOL(mdesc_get_node);
 
 int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,
 			const char *node_name, union md_node_info *node_info)
@@ -603,6 +604,7 @@ int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,
 
 	return 0;
 }
+EXPORT_SYMBOL(mdesc_get_node_info);
 
 static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
 {
diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c
index ea63f02cab3f..624f0a98edfe 100644
--- a/arch/sparc/kernel/vio.c
+++ b/arch/sparc/kernel/vio.c
@@ -217,6 +217,32 @@ static const u64 *vio_cfg_handle(struct mdesc_handle *hp, u64 node)
 	return cfg_handle;
 }
 
+/**
+ * vio_vdev_node() - Find VDEV node in MD
+ * @hp:  Handle to the MD
+ * @vdev:  Pointer to VDEV
+ *
+ * Find the node in the current MD which matches the given vio_dev. This
+ * must be done dynamically since the node value can change if the MD
+ * is updated.
+ *
+ * NOTE: the MD must be locked, using mdesc_grab(), when calling this routine
+ *
+ * Return: The VDEV node in MDESC
+ */
+u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev)
+{
+	u64 node;
+
+	if (vdev == NULL)
+		return MDESC_NODE_NULL;
+
+	node = mdesc_get_node(hp, (const char *)vdev->node_name,
+			      &vdev->md_node_info);
+
+	return node;
+}
+
 static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
 				  struct vio_dev *vdev)
 {
@@ -316,16 +342,13 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
 	if (!id) {
 		dev_set_name(&vdev->dev, "%s", type);
 		vdev->dev_no = ~(u64)0;
-		vdev->id = ~(u64)0;
 	} else if (!cfg_handle) {
 		dev_set_name(&vdev->dev, "%s-%llu", type, *id);
 		vdev->dev_no = *id;
-		vdev->id = ~(u64)0;
 	} else {
 		dev_set_name(&vdev->dev, "%s-%llu-%llu", type,
 			     *cfg_handle, *id);
 		vdev->dev_no = *cfg_handle;
-		vdev->id = *id;
 	}
 
 	vdev->dev.parent = parent;
@@ -347,11 +370,24 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
 	}
 	vdev->dp = dp;
 
-	/* node_name is NULL for the parent/channel-devices node */
-	if (node_name != NULL)
+	/*
+	 * node_name is NULL for the parent/channel-devices node and
+	 * the parent doesn't require the MD node info.
+	 */
+	if (node_name != NULL) {
 		(void) snprintf(vdev->node_name, VIO_MAX_NAME_LEN, "%s",
 				node_name);
 
+		err = mdesc_get_node_info(hp, mp, node_name,
+					  &vdev->md_node_info);
+		if (err) {
+			pr_err("VIO: Could not get MD node info %s, err=%d\n",
+			       dev_name(&vdev->dev), err);
+			kfree(vdev);
+			return NULL;
+		}
+	}
+
 	pr_info("VIO: Adding device %s (tx_ino = %llx, rx_ino = %llx)\n",
 		dev_name(&vdev->dev), vdev->tx_ino, vdev->rx_ino);
 
@@ -375,68 +411,36 @@ static void vio_add(struct mdesc_handle *hp, u64 node,
 	(void) vio_create_one(hp, node, node_name, &root_vdev->dev);
 }
 
-struct vio_md_node_query {
-	const char *type;
-	u64 dev_no;
-	u64 id;
+struct vio_remove_node_data {
+	struct mdesc_handle *hp;
+	u64 node;
 };
 
 static int vio_md_node_match(struct device *dev, void *arg)
 {
-	struct vio_md_node_query *query = (struct vio_md_node_query *) arg;
 	struct vio_dev *vdev = to_vio_dev(dev);
+	struct vio_remove_node_data *node_data;
+	u64 node;
 
-	if (vdev->dev_no != query->dev_no)
-		return 0;
-	if (vdev->id != query->id)
-		return 0;
-	if (strcmp(vdev->type, query->type))
-		return 0;
+	node_data = (struct vio_remove_node_data *)arg;
 
-	return 1;
+	node = vio_vdev_node(node_data->hp, vdev);
+
+	if (node == node_data->node)
+		return 1;
+	else
+		return 0;
 }
 
 static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name)
 {
-	const char *type;
-	const u64 *id, *cfg_handle;
-	u64 a;
-	struct vio_md_node_query query;
+	struct vio_remove_node_data node_data;
 	struct device *dev;
 
-	type = mdesc_get_property(hp, node, "device-type", NULL);
-	if (!type) {
-		type = mdesc_get_property(hp, node, "name", NULL);
-		if (!type)
-			type = mdesc_node_name(hp, node);
-	}
-
-	query.type = type;
-
-	id = mdesc_get_property(hp, node, "id", NULL);
-	cfg_handle = NULL;
-	mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
-		u64 target;
-
-		target = mdesc_arc_target(hp, a);
-		cfg_handle = mdesc_get_property(hp, target,
-						"cfg-handle", NULL);
-		if (cfg_handle)
-			break;
-	}
-
-	if (!id) {
-		query.dev_no = ~(u64)0;
-		query.id = ~(u64)0;
-	} else if (!cfg_handle) {
-		query.dev_no = *id;
-		query.id = ~(u64)0;
-	} else {
-		query.dev_no = *cfg_handle;
-		query.id = *id;
-	}
+	node_data.hp = hp;
+	node_data.node = node;
 
-	dev = device_find_child(&root_vdev->dev, &query,
+	dev = device_find_child(&root_vdev->dev, (void *)&node_data,
 				vio_md_node_match);
 	if (dev) {
 		printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));
@@ -444,15 +448,7 @@ static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name)
 		device_unregister(dev);
 		put_device(dev);
 	} else {
-		if (!id)
-			printk(KERN_ERR "VIO: Removed unknown %s node.\n",
-			       type);
-		else if (!cfg_handle)
-			printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n",
-			       type, *id);
-		else
-			printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n",
-			       type, *cfg_handle, *id);
+		pr_err("VIO: %s node not found in MDESC\n", node_name);
 	}
 }