From: Rusty Russell <rusty@rustcorp.com.au>
To: Xen Mailing List <xen-devel@lists.xensource.com>
Subject: [PATCH 6/9] Linux support for vdevice bus
Date: Tue, 06 Jun 2006 15:54:46 +1000 [thread overview]
Message-ID: <1149573287.5183.41.camel@localhost.localdomain> (raw)
In-Reply-To: <1149572143.5183.25.camel@localhost.localdomain>
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
next prev parent reply other threads:[~2006-06-06 5:54 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-06-06 5:35 [PATCH 1/9] Xen Share: Simplified I/O Mechanism Rusty Russell
2006-06-06 5:50 ` [PATCH 3/9] privcmd interface addition to support share operations from Dom0 userspace Rusty Russell
2006-06-06 5:51 ` [PATCH 4/9] /dev/xenshare for accessing/mapping shared pages from userspace Rusty Russell
2006-06-06 5:52 ` [PATCH 5/9] Vdevice share in start_info Rusty Russell
2006-06-06 5:54 ` Rusty Russell [this message]
2006-06-07 10:03 ` [PATCH 6/9] Linux support for vdevice bus Jacob Gorm Hansen
2006-06-07 10:58 ` Rusty Russell
2006-06-07 11:09 ` Jacob Gorm Hansen
2006-06-06 5:55 ` [PATCH 7/9] vdevice tool for manipulating " Rusty Russell
2006-06-06 5:57 ` [PATCH 8/9] Xen Share Net Device Rusty Russell
2006-06-06 5:58 ` [PATCH 2/9] Linux kernel infrastructure for Xen Share access Rusty Russell
2006-06-14 17:26 ` Mike D. Day
2006-06-06 5:59 ` [PATCH 9/9] Simple Xenshare Block Device and userspace backend Rusty Russell
2006-06-06 14:31 ` [PATCH 1/9] Xen Share: Simplified I/O Mechanism Harry Butterworth
2006-06-07 2:24 ` Rusty Russell
2006-06-06 14:47 ` Harry Butterworth
2006-06-07 2:35 ` Rusty Russell
2006-06-07 13:31 ` Harry Butterworth
2006-06-14 17:46 ` Mike D. Day
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1149573287.5183.41.camel@localhost.localdomain \
--to=rusty@rustcorp.com.au \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.