WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 6/9] Linux support for vdevice bus

To: Xen Mailing List <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 6/9] Linux support for vdevice bus
From: Rusty Russell <rusty@xxxxxxxxxxxxxxx>
Date: Tue, 06 Jun 2006 15:54:46 +1000
Delivery-date: Mon, 05 Jun 2006 22:55:23 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <1149572143.5183.25.camel@xxxxxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1149572143.5183.25.camel@xxxxxxxxxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
Subject: Linux support for vdevice bus

This patch provides the Linux implementation of the vdevice bus.

FIXME: currently it does not support save/restore of the domain: it
should call stop before shutting down, and remap shares afterwards
before calling reconnect.  This depends on exactly what we do with
shared pages on restore.

diff -r 520f3bf7d3f0 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Fri Jun  2 05:22:39 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Fri Jun  2 17:04:48 2006
@@ -8,6 +8,7 @@
 obj-y  += balloon/
 obj-y  += privcmd/
 obj-y  += xenbus/
+obj-y  += vdevice/
 obj-y  += xenshare.o
 
 obj-$(CONFIG_XEN_BLKDEV_BACKEND)       += blkback/
diff -r 520f3bf7d3f0 linux-2.6-xen-sparse/drivers/xen/vdevice/Makefile
--- /dev/null   Fri Jun  2 05:22:39 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/vdevice/Makefile Fri Jun  2 17:04:48 2006
@@ -0,0 +1,1 @@
+obj-y := vdevice.o
diff -r 520f3bf7d3f0 linux-2.6-xen-sparse/drivers/xen/vdevice/vdevice.c
--- /dev/null   Fri Jun  2 05:22:39 2006
+++ b/linux-2.6-xen-sparse/drivers/xen/vdevice/vdevice.c        Fri Jun  2 
17:04:48 2006
@@ -0,0 +1,286 @@
+#define DEBUG
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/vdevice.h>
+#include <linux/page-flags.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <xen/evtchn.h>
+#include <asm/page.h>
+#include <xen/interface/share.h>
+
+static struct work_struct vdevice_add;
+static struct xen_share *vdevice_share;
+static struct vdevice_desc *vdevices;
+static int vdevice_change_counter = 1;
+static struct device **devices_installed;
+
+static ssize_t show_ref(struct bus_type *bus, char *buf)
+{
+       return sprintf(buf, "0x%lx\n", xen_start_info->vdevice_share);
+}
+static BUS_ATTR(share_ref, 0444, show_ref, NULL);
+
+static ssize_t type_show(struct device *_dev, 
+                         struct device_attribute *attr, char *buf)
+{
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       return sprintf(buf, "%i", dev->id.type);
+}
+static ssize_t features_show(struct device *_dev, 
+                             struct device_attribute *attr, char *buf)
+{
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       return sprintf(buf, "%i", dev->id.features);
+}
+static ssize_t share_ref_show(struct device *_dev, 
+                              struct device_attribute *attr, char *buf)
+{
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       return sprintf(buf, "%li",
+                      (long)vdevices[dev->vdevice_index].shared_ref);
+}
+static ssize_t status_show(struct device *_dev, 
+                           struct device_attribute *attr, char *buf)
+{
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       return sprintf(buf, "%i", vdevices[dev->vdevice_index].status);
+}
+static ssize_t status_store(struct device *_dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       if (sscanf(buf, "%i", &vdevices[dev->vdevice_index].status) != 1)
+               return -EINVAL;
+       return count;
+}
+static struct device_attribute vdevice_dev_attrs[] = {
+       __ATTR_RO(type),
+       __ATTR_RO(features),
+       __ATTR_RO(share_ref),
+       __ATTR(status, 0644, status_show, status_store),
+       __ATTR_NULL
+};
+
+static int vdevice_match(struct device *_dev, struct device_driver *_drv)
+{
+       const struct vdevice_id *i;
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       struct vdevice_driver *drv = container_of(_drv, struct vdevice_driver,
+                                                driver);
+
+       for (i = drv->ids; i->type != 0; i++) {
+               if (dev->id.type == i->type &&
+                   (dev->id.features & i->features) == i->features)
+                       return 1;
+       }
+       return 0;
+}
+
+struct vdevice_bus {
+       struct bus_type bus;
+       struct vdevice dev;
+};
+
+static struct vdevice_bus vd_bus = {
+       .bus = {
+               .name  = "vdevice",
+               .match = vdevice_match,
+               .dev_attrs = vdevice_dev_attrs,
+       },
+       .dev.dev = {
+               .parent = NULL,
+               .bus_id = "vdevice",
+       }
+};
+
+static int vdevice_dev_probe(struct device *_dev)
+{
+       int ret;
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       struct vdevice_driver *drv = container_of(dev->dev.driver, 
+                       struct vdevice_driver, driver);
+       struct vdevice_desc *me = &vdevices[dev->vdevice_index];
+
+       me->status |= VDEVICE_S_DRIVER;
+
+       /* We only set this up when we actually probe, as userspace
+        * drivers don't want this.  Previous probe might have failed,
+        * so we could already have it mapped. */
+       if (!dev->share) {
+               dev->share = xen_share_get(me->shared_ref, me->nr_pages);
+               if (IS_ERR(dev->share)) {
+                       printk(KERN_ERR
+                              "vdevice: failed mapping %u@%li for %i/%i\n",
+                              me->nr_pages, (long)me->shared_ref,
+                              dev->id.type, dev->id.features);
+                       me->status |= VDEVICE_S_FAILED;
+                       ret = PTR_ERR(dev->share);
+                       dev->share = NULL;
+                       return ret;
+               }
+               me->status |= VDEVICE_S_MAPPED;
+       }
+
+       ret = drv->probe(dev, &dev->id);
+       if (ret == 0)
+               me->status |= VDEVICE_S_DRIVER_OK;
+       return ret;
+}
+
+static int vdevice_dev_remove(struct device *_dev)
+{
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+       struct vdevice_driver *drv = container_of(dev->dev.driver, 
+                       struct vdevice_driver, driver);
+
+       if (drv && drv->remove)
+               drv->remove(dev);
+       if (dev->share)
+               xen_share_put(dev->share);
+       put_device(_dev);
+       return 0;
+}
+
+int register_vdevice_driver(struct vdevice_driver *drv)
+{
+       drv->driver.bus = &vd_bus.bus;
+       drv->driver.name = drv->name;
+       drv->driver.owner = drv->owner;
+       drv->driver.probe = vdevice_dev_probe;
+       drv->driver.remove = vdevice_dev_remove;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(register_vdevice_driver);
+
+void unregister_vdevice_driver(struct vdevice_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(unregister_vdevice_driver);
+
+static share_ref_t new_shared_page(void)
+{              
+       dom0_op_t op = { .cmd = DOM0_CREATESHAREDPAGES, 
+                        .interface_version = DOM0_INTERFACE_VERSION,
+                        .u.createsharedpages.num = 1 };
+
+       return HYPERVISOR_dom0_op(&op);
+}
+
+static void release_vdevice(struct device *_dev)
+{
+       struct vdevice *dev = container_of(_dev, struct vdevice, dev);
+
+       devices_installed[dev->vdevice_index] = NULL;
+       kfree(dev);
+}      
+       
+static void add_vdevice(unsigned int num)
+{
+       struct vdevice *new;
+
+       vdevices[num].status = VDEVICE_S_ACKNOWLEDGE;
+       new = kmalloc(sizeof(struct vdevice), GFP_KERNEL);
+       if (!new) {
+               printk(KERN_EMERG "Could not allocate vdevice %u\n", num);
+               vdevices[num].status |= VDEVICE_S_FAILED;
+               return;
+       }
+
+       new->vdevice_index = num;
+       new->id = vdevices[num].id;
+       new->private = NULL;
+       memset(&new->dev, 0, sizeof(new->dev));
+       new->dev.parent = &vd_bus.dev.dev;
+       new->dev.bus = &vd_bus.bus;
+       new->dev.release = release_vdevice;
+       sprintf(new->dev.bus_id, "%u", num);
+       new->share = NULL;
+       if (device_register(&new->dev) != 0) {
+               printk(KERN_EMERG "Could not register vdevice %u\n", num);
+               vdevices[num].status |= VDEVICE_S_FAILED;
+               kfree(new);
+       }
+
+       devices_installed[num] = &new->dev;
+}
+
+static void vdevice_work(void *unused)
+{
+       unsigned int i;
+
+       /* Something changed: look for differences. */
+       for (i = 0; i < PAGE_SIZE / sizeof(struct vdevice_desc); i++) {
+               char name[20];
+               struct device *dev;
+
+               sprintf(name, "%i", i);
+               dev = devices_installed[i];
+               if (vdevices[i].id.type != 0 && !dev)
+                       add_vdevice(i);
+               else if (dev && vdevices[i].id.type == 0)
+                       device_unregister(dev);
+       }
+
+       /* Re-arm trigger */
+       vdevice_change_counter = 1;
+
+       /* Acknowledge. */
+       HYPERVISOR_share(XEN_SHARE_trigger, xen_start_info->vdevice_share,
+                        0, 0, 0);
+}
+
+static void vdevice_handler(struct xen_share_handler *h)
+{
+       schedule_work(&vdevice_add);
+}
+static struct xen_share_handler handler = {
+       .handler = vdevice_handler,
+};
+
+static int __init vdevice_init(void)
+{
+       int err;
+
+       if (!xen_start_info->vdevice_share) {
+               /* We could be dom0, in which case we can create it. */
+               xen_start_info->vdevice_share = new_shared_page();
+               if (IS_ERR_VALUE(xen_start_info->vdevice_share)) {
+                       printk(KERN_INFO "Vdevice bus not found\n");
+                       xen_start_info->vdevice_share = 0;
+                       return 0;
+               }
+       }
+       printk(KERN_INFO "vdevice bus found at 0x%lx\n", 
xen_start_info->vdevice_share);
+
+       vdevice_share = xen_share_get(xen_start_info->vdevice_share, 1);
+       BUG_ON(IS_ERR(vdevice_share));
+       vdevices = vdevice_share->addr;
+
+       /* Allocate space for the same number of devices as can fit
+        * on the vdevices page */
+       devices_installed = kcalloc(sizeof(struct device*),
+                                PAGE_SIZE / sizeof(struct vdevice_desc),
+                                GFP_KERNEL);
+       BUG_ON(!devices_installed);
+
+       bus_register(&vd_bus.bus);
+       device_register(&vd_bus.dev.dev);
+       bus_create_file(&vd_bus.bus, &bus_attr_share_ref);
+
+       /* Scan bus once for existing devices before setting up interrupt */
+       vdevice_work(NULL);
+
+       INIT_WORK(&vdevice_add, vdevice_work, NULL);
+       xen_share_add_handler(vdevice_share, &handler);
+       err = xen_share_watch(vdevice_share, 1, &vdevice_change_counter);
+       BUG_ON(err<0);
+
+       return 0;
+}
+postcore_initcall(vdevice_init);
diff -r 520f3bf7d3f0 linux-2.6-xen-sparse/include/linux/vdevice.h
--- /dev/null   Fri Jun  2 05:22:39 2006
+++ b/linux-2.6-xen-sparse/include/linux/vdevice.h      Fri Jun  2 17:04:48 2006
@@ -0,0 +1,40 @@
+#ifndef _LINUX_VDEVICE_H_
+#define _LINUX_VDEVICE_H_
+
+#include <linux/device.h>
+#include <xen/interface/io/vdevice.h>
+#include <xen/interface/share.h>
+#include <asm/share.h>
+
+struct vdevice {
+       /* Unique busid */
+       int vdevice_index;
+
+       /* Shared region for this device. */
+       struct xen_share *share;
+
+       struct device dev;
+       struct vdevice_id id;
+
+       /* Driver can hang data off here. */
+       void *private;
+};
+
+struct vdevice_driver {
+       /* I can drive the following type of device(s) */
+       char *name;
+       struct module *owner;
+       const struct vdevice_id *ids;
+       int (*probe)(struct vdevice *dev, const struct vdevice_id *id);
+       void (*remove)(struct vdevice *dev);
+
+       void (*stop)(struct vdevice *dev);
+       int (*reconnect)(struct vdevice *dev);
+
+       struct device_driver driver;
+};
+
+extern int register_vdevice_driver(struct vdevice_driver *drv);
+extern void unregister_vdevice_driver(struct vdevice_driver *drv);
+
+#endif /* _LINUX_VDEVICE_H_ */

-- 
 ccontrol: http://ccontrol.ozlabs.org


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel