Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[linux-2.6-microblaze.git] / drivers / virtio / virtio.c
index 1ea0c1f..588e02f 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/virtio_config.h>
 #include <linux/module.h>
 #include <linux/idr.h>
+#include <linux/of.h>
 #include <uapi/linux/virtio_ids.h>
 
 /* Unique numbering for virtio devices. */
@@ -292,6 +293,8 @@ static void virtio_dev_remove(struct device *_d)
 
        /* Acknowledge the device's existence again. */
        virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
+
+       of_node_put(dev->dev.of_node);
 }
 
 static struct bus_type virtio_bus = {
@@ -318,6 +321,43 @@ void unregister_virtio_driver(struct virtio_driver *driver)
 }
 EXPORT_SYMBOL_GPL(unregister_virtio_driver);
 
+static int virtio_device_of_init(struct virtio_device *dev)
+{
+       struct device_node *np, *pnode = dev_of_node(dev->dev.parent);
+       char compat[] = "virtio,deviceXXXXXXXX";
+       int ret, count;
+
+       if (!pnode)
+               return 0;
+
+       count = of_get_available_child_count(pnode);
+       if (!count)
+               return 0;
+
+       /* There can be only 1 child node */
+       if (WARN_ON(count > 1))
+               return -EINVAL;
+
+       np = of_get_next_available_child(pnode, NULL);
+       if (WARN_ON(!np))
+               return -ENODEV;
+
+       ret = snprintf(compat, sizeof(compat), "virtio,device%x", dev->id.device);
+       BUG_ON(ret >= sizeof(compat));
+
+       if (!of_device_is_compatible(np, compat)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       dev->dev.of_node = np;
+       return 0;
+
+out:
+       of_node_put(np);
+       return ret;
+}
+
 /**
  * register_virtio_device - register virtio device
  * @dev        : virtio device to be registered
@@ -342,6 +382,10 @@ int register_virtio_device(struct virtio_device *dev)
        dev->index = err;
        dev_set_name(&dev->dev, "virtio%u", dev->index);
 
+       err = virtio_device_of_init(dev);
+       if (err)
+               goto out_ida_remove;
+
        spin_lock_init(&dev->config_lock);
        dev->config_enabled = false;
        dev->config_change_pending = false;
@@ -362,10 +406,16 @@ int register_virtio_device(struct virtio_device *dev)
         */
        err = device_add(&dev->dev);
        if (err)
-               ida_simple_remove(&virtio_index_ida, dev->index);
+               goto out_of_node_put;
+
+       return 0;
+
+out_of_node_put:
+       of_node_put(dev->dev.of_node);
+out_ida_remove:
+       ida_simple_remove(&virtio_index_ida, dev->index);
 out:
-       if (err)
-               virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
+       virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
        return err;
 }
 EXPORT_SYMBOL_GPL(register_virtio_device);