4.9-stable review patch.  If anyone has any objections, please let me know.

------------------

From: James Clarke <[email protected]>


[ Upstream commit c982aa9c304bf0b9a7522fd118fed4afa5a0263c ]

VIO devices were being looked up by their index in the machine
description node block, but this often varies over time as devices are
added and removed. Instead, store the ID and look up using the type,
config handle and ID.

Signed-off-by: James Clarke <[email protected]>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112541
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 arch/sparc/include/asm/vio.h |    1 
 arch/sparc/kernel/vio.c      |   68 ++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 65 insertions(+), 4 deletions(-)

--- a/arch/sparc/include/asm/vio.h
+++ b/arch/sparc/include/asm/vio.h
@@ -327,6 +327,7 @@ struct vio_dev {
        int                     compat_len;
 
        u64                     dev_no;
+       u64                     id;
 
        unsigned long           channel_id;
 
--- a/arch/sparc/kernel/vio.c
+++ b/arch/sparc/kernel/vio.c
@@ -302,13 +302,16 @@ static struct vio_dev *vio_create_one(st
        if (!id) {
                dev_set_name(&vdev->dev, "%s", bus_id_name);
                vdev->dev_no = ~(u64)0;
+               vdev->id = ~(u64)0;
        } else if (!cfg_handle) {
                dev_set_name(&vdev->dev, "%s-%llu", bus_id_name, *id);
                vdev->dev_no = *id;
+               vdev->id = ~(u64)0;
        } else {
                dev_set_name(&vdev->dev, "%s-%llu-%llu", bus_id_name,
                             *cfg_handle, *id);
                vdev->dev_no = *cfg_handle;
+               vdev->id = *id;
        }
 
        vdev->dev.parent = parent;
@@ -351,27 +354,84 @@ static void vio_add(struct mdesc_handle
        (void) vio_create_one(hp, node, &root_vdev->dev);
 }
 
+struct vio_md_node_query {
+       const char *type;
+       u64 dev_no;
+       u64 id;
+};
+
 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);
 
-       if (vdev->mp == (u64) arg)
-               return 1;
+       if (vdev->dev_no != query->dev_no)
+               return 0;
+       if (vdev->id != query->id)
+               return 0;
+       if (strcmp(vdev->type, query->type))
+               return 0;
 
-       return 0;
+       return 1;
 }
 
 static void vio_remove(struct mdesc_handle *hp, u64 node)
 {
+       const char *type;
+       const u64 *id, *cfg_handle;
+       u64 a;
+       struct vio_md_node_query query;
        struct device *dev;
 
-       dev = device_find_child(&root_vdev->dev, (void *) node,
+       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;
+       }
+
+       dev = device_find_child(&root_vdev->dev, &query,
                                vio_md_node_match);
        if (dev) {
                printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));
 
                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);
        }
 }
 


Reply via email to