sparc64: Enhance search for VIO device in MDESC
authorJag Raman <jag.raman@oracle.com>
Fri, 23 Jun 2017 18:58:39 +0000 (14:58 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sun, 25 Jun 2017 20:43:14 +0000 (13:43 -0700)
Enhances search for VIO device in MDESC by leveraging already existing
MDESC APIs. Enhances changes in earlier patch,
"sparc: Machine description indices can vary", by using existing MD
search functions. It also specifies a match function, thereby
enabling device_find_child() to use it for the purpose of matching
device nodes in MDESC.

An API to find VDEV node in MDESC based on its md_node_info is also
added. It is planned to be used by VIO device clients in the future.

Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
Reviewed-by: Shannon Nelson <shannon.nelson@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/include/asm/vio.h
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/vio.c

index d8eb195b69e3623925c7d6195e2535c1319cafc8..25ede61c038634910bbf7f411e5440a955c02dd4 100644 (file)
@@ -329,7 +329,6 @@ struct vio_dev {
        int                     compat_len;
 
        u64                     dev_no;
-       u64                     id;
 
        unsigned long           channel_id;
 
@@ -341,6 +340,9 @@ struct vio_dev {
        /* Handle to the root of "channel-devices" sub-tree in MDESC */
        u64                     cdev_handle;
 
+       /* MD specific data used to identify the vdev in MD */
+       union md_node_info      md_node_info;
+
        struct device           dev;
 };
 
@@ -497,5 +499,6 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
 
 void vio_port_up(struct vio_driver_state *vio);
 int vio_set_intr(unsigned long dev_ino, int state);
+u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev);
 
 #endif /* _SPARC64_VIO_H */
index f795ee015738f466177d2f208a213d528c814588..e4b4e790bf899cb295bb7add3275140df55da17c 100644 (file)
@@ -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)
 {
index ea63f02cab3fdbaa372c07f9f5dd3d86d6aad695..624f0a98edfee0477b31bd857748c2695994a3f8 100644 (file)
@@ -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);
        }
 }