What purpose this virtio platform driver serves? Are you trying to make driver layers here and each virtio device driver can hook up into this platform driver. Is that correct ? Thanks -Bharat > -----Original Message----- > From: virtualization-bounces@xxxxxxxxxxxxxxxxxxxxxxxxxx > [mailto:virtualization-bounces@xxxxxxxxxxxxxxxxxxxxxxxxxx] On Behalf Of > Magnus Damm > Sent: Tuesday, June 21, 2011 3:56 PM > To: linux-kernel@xxxxxxxxxxxxxxx > Cc: vapier@xxxxxxxxxx; mst@xxxxxxxxxx; linux-sh@xxxxxxxxxxxxxxx; Magnus > Damm; virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx > Subject: [PATCH 02/02] virtio: Add virtio platform driver > > From: Magnus Damm <damm@xxxxxxxxxxxxx> > > This patch adds a virtio platform driver. The code is based on the lguest > implementation available in drivers/lguest/lguest_device.c > > The iomem resource is used to point out the lguest device descriptor, and > the platform data contains two separate callbacks for notification. > > Signed-off-by: Magnus Damm <damm@xxxxxxxxxxxxx> > --- > > drivers/virtio/Kconfig | 11 + > drivers/virtio/Makefile | 1 > drivers/virtio/virtio_platform.c | 282 > ++++++++++++++++++++++++++++++++++++++ > include/linux/virtio_platform.h | 12 + > 4 files changed, 306 insertions(+) > > --- 0002/drivers/virtio/Kconfig > +++ work/drivers/virtio/Kconfig 2011-03-03 15:56:53.000000000 +0900 > @@ -35,3 +35,14 @@ config VIRTIO_BALLOON > > config VIRTIO_LGUEST > tristate > + > +config VIRTIO_PLATFORM > + tristate "Platform driver for virtio devices (EXPERIMENTAL)" > + select VIRTIO > + select VIRTIO_RING > + select VIRTIO_LGUEST > + ---help--- > + This drivers provides support for virtio based paravirtual device > + drivers over a platform bus. > + > + If unsure, say N. > --- 0002/drivers/virtio/Makefile > +++ work/drivers/virtio/Makefile 2011-03-03 15:56:53.000000000 +0900 > @@ -3,3 +3,4 @@ obj-$(CONFIG_VIRTIO_RING) += virtio_ring > obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o > obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o > obj-$(CONFIG_VIRTIO_LGUEST) += virtio_lguest.o > +obj-$(CONFIG_VIRTIO_PLATFORM) += virtio_platform.o > --- /dev/null > +++ work/drivers/virtio/virtio_platform.c 2011-03-03 16:07:31.000000000 > +0900 > @@ -0,0 +1,282 @@ > +#include <linux/init.h> > +#include <linux/virtio.h> > +#include <linux/virtio_config.h> > +#include <linux/virtio_ring.h> > +#include <linux/lguest_device.h> > +#include <linux/lguest_launcher.h> > +#include <linux/virtio_platform.h> > +#include <linux/platform_device.h> > +#include <linux/interrupt.h> > +#include <linux/err.h> > +#include <linux/slab.h> > +#include <linux/io.h> > + > +static void __iomem *virtio_map(unsigned long phys_addr, unsigned long > +pages) { > + return ioremap_nocache(phys_addr, PAGE_SIZE*pages); } > + > +static void virtio_unmap(void __iomem *addr) { > + iounmap(addr); > +} > + > +static void set_status(struct virtio_device *vdev, u8 status) { > + struct platform_device *pdev = to_platform_device(vdev- > >dev.parent); > + struct virtio_platform_data *pdata = pdev->dev.platform_data; > + > + to_lgdev(vdev)->desc->status = status; > + pdata->notify_virtio(pdev); > +} > + > +static void lg_set_status(struct virtio_device *vdev, u8 status) { > + BUG_ON(!status); > + set_status(vdev, status); > +} > + > +static void lg_reset(struct virtio_device *vdev) { > + set_status(vdev, 0); > +} > + > +/* > + * Virtqueues > + * > + * The other piece of infrastructure virtio needs is a "virtqueue": a > +way of > + * the Guest device registering buffers for the other side to read from > +or > + * write into (ie. send and receive buffers). Each device can have > +multiple > + * virtqueues: for example the console driver uses one queue for > +sending and > + * another for receiving. > + * > + * Fortunately for us, a very fast shared-memory-plus-descriptors > +virtqueue > + * already exists in virtio_ring.c. We just need to connect it up. > + * > + * We start with the information we need to keep about each virtqueue. > + */ > + > +/*D:140 This is the information we remember about each virtqueue. */ > +struct lguest_vq_info { > + /* A copy of the information contained in the device config. */ > + struct lguest_vqconfig config; > + > + /* The address where we mapped the virtio ring, so we can unmap it. > */ > + void __iomem *pages; > +}; > + > +/* > + * When the virtio_ring code wants to prod the Host, it calls us here > +and we > + * call the board specific callback. We hand a pointer to the > +configuration > + * so the board code knows which virtqueue we're talking about. > + */ > +static void lg_notify(struct virtqueue *vq) { > + struct platform_device *pdev = to_platform_device(vq->vdev- > >dev.parent); > + struct virtio_platform_data *pdata = pdev->dev.platform_data; > + struct lguest_vq_info *lvq = vq->priv; > + > + pdata->notify_virtqueue(pdev, &lvq->config); } > + > +/* > + * This routine finds the Nth virtqueue described in the configuration > +of > + * this device and sets it up. > + * > + * This is kind of an ugly duckling. It'd be nicer to have a standard > + * representation of a virtqueue in the configuration space, but it > +seems that > + * everyone wants to do it differently. The KVM coders want the Guest > +to > + * allocate its own pages and tell the Host where they are, but for > +lguest it's > + * simpler for the Host to simply tell us where the pages are. > + */ > +static struct virtqueue *lg_find_vq(struct virtio_device *vdev, > + unsigned index, > + void (*callback)(struct virtqueue *vq), > + const char *name) > +{ > + struct lguest_device *ldev = to_lgdev(vdev); > + struct lguest_vq_info *lvq; > + struct virtqueue *vq; > + int err; > + > + /* We must have this many virtqueues. */ > + if (index >= ldev->desc->num_vq) > + return ERR_PTR(-ENOENT); > + > + lvq = kmalloc(sizeof(*lvq), GFP_KERNEL); > + if (!lvq) > + return ERR_PTR(-ENOMEM); > + > + /* > + * Make a copy of the "struct lguest_vqconfig" entry, which sits > after > + * the descriptor. We need a copy because the config space might > not > + * be aligned correctly. > + */ > + memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config)); > + > + dev_info(&vdev->dev, "Mapping virtqueue %i addr %lx\n", index, > + (unsigned long)lvq->config.pfn << PAGE_SHIFT); > + /* Figure out how many pages the ring will take, and map that > memory */ > + lvq->pages = virtio_map((unsigned long)lvq->config.pfn << > PAGE_SHIFT, > + DIV_ROUND_UP(vring_size(lvq->config.num, > + LGUEST_VRING_ALIGN), > + PAGE_SIZE)); > + if (!lvq->pages) { > + err = -ENOMEM; > + goto free_lvq; > + } > + > + /* > + * OK, tell virtio_ring.c to set up a virtqueue now we know its > size > + * and we've got a pointer to its pages. > + */ > + vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, > + vdev, lvq->pages, lg_notify, callback, name); > + if (!vq) { > + err = -ENOMEM; > + goto unmap; > + } > + > + /* > + * Tell the interrupt for this virtqueue to go to the virtio_ring > + * interrupt handler. > + * > + * FIXME: We used to have a flag for the Host to tell us we could > use > + * the interrupt as a source of randomness: it'd be nice to have > that > + * back. > + */ > + err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED, > + dev_name(&vdev->dev), vq); > + if (err) > + goto destroy_vring; > + > + /* > + * Last of all we hook up our 'struct lguest_vq_info" to the > + * virtqueue's priv pointer. > + */ > + vq->priv = lvq; > + return vq; > + > +destroy_vring: > + vring_del_virtqueue(vq); > +unmap: > + virtio_unmap(lvq->pages); > +free_lvq: > + kfree(lvq); > + return ERR_PTR(err); > +} > +/*:*/ > + > +/* Cleaning up a virtqueue is easy */ > +static void lg_del_vq(struct virtqueue *vq) { > + struct lguest_vq_info *lvq = vq->priv; > + > + /* Release the interrupt */ > + free_irq(lvq->config.irq, vq); > + /* Tell virtio_ring.c to free the virtqueue. */ > + vring_del_virtqueue(vq); > + /* Unmap the pages containing the ring. */ > + virtio_unmap(lvq->pages); > + /* Free our own queue information. */ > + kfree(lvq); > +} > + > +static void lg_del_vqs(struct virtio_device *vdev) { > + struct virtqueue *vq, *n; > + > + list_for_each_entry_safe(vq, n, &vdev->vqs, list) > + lg_del_vq(vq); > +} > + > +static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs, > + struct virtqueue *vqs[], > + vq_callback_t *callbacks[], > + const char *names[]) > +{ > + struct lguest_device *ldev = to_lgdev(vdev); > + int i; > + > + /* We must have this many virtqueues. */ > + if (nvqs > ldev->desc->num_vq) > + return -ENOENT; > + > + for (i = 0; i < nvqs; ++i) { > + vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]); > + if (IS_ERR(vqs[i])) > + goto error; > + } > + return 0; > + > +error: > + lg_del_vqs(vdev); > + return PTR_ERR(vqs[i]); > +} > + > +/* The ops structure which hooks everything together. */ static struct > +virtio_config_ops lguest_config_ops = { > + .get_features = lg_get_features, > + .finalize_features = lg_finalize_features, > + .get = lg_get, > + .set = lg_set, > + .get_status = lg_get_status, > + .set_status = lg_set_status, > + .reset = lg_reset, > + .find_vqs = lg_find_vqs, > + .del_vqs = lg_del_vqs, > +}; > + > +static int virtio_platform_probe(struct platform_device *pdev) { > + struct virtio_platform_data *pdata = pdev->dev.platform_data; > + struct resource *res; > + void *devices; > + > + if (!pdata) { > + dev_err(&pdev->dev, "no platform data defined\n"); > + return -EINVAL; > + } > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (res == NULL) { > + dev_err(&pdev->dev, "cannot find IO resource\n"); > + return -ENOENT; > + } > + > + /* Devices are pointed out using struct resource */ > + devices = virtio_map(res->start, resource_size(res) >> PAGE_SHIFT); > + lg_scan_devices(devices, &pdev->dev, &lguest_config_ops); > + return 0; > +} > + > +static int virtio_platform_remove(struct platform_device *pdev) { > + return -ENOTSUPP; > +} > + > +static struct platform_driver virtio_platform_driver = { > + .driver = { > + .name = "virtio-platform", > + .owner = THIS_MODULE, > + }, > + .probe = virtio_platform_probe, > + .remove = virtio_platform_remove, > +}; > + > +static int __init virtio_platform_init(void) { > + return platform_driver_register(&virtio_platform_driver); > +} > + > +static void __exit virtio_platform_exit(void) { > + platform_driver_unregister(&virtio_platform_driver); > +} > + > +module_init(virtio_platform_init); > +module_exit(virtio_platform_exit); > + > +MODULE_DESCRIPTION("VirtIO Platform Driver"); MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:virtio-platform"); > --- /dev/null > +++ work/include/linux/virtio_platform.h 2011-03-03 15:56:54.000000000 > +0900 > @@ -0,0 +1,12 @@ > +#ifndef _LINUX_VIRTIO_PLATFORM_H > +#define _LINUX_VIRTIO_PLATFORM_H > +#include <linux/platform_device.h> > +#include <linux/lguest_launcher.h> > + > +struct virtio_platform_data { > + void (*notify_virtio)(struct platform_device *pdev); > + void (*notify_virtqueue)(struct platform_device *pdev, > + struct lguest_vqconfig *config); > +}; > + > +#endif /* _LINUX_VIRTIO_PLATFORM_H */ > _______________________________________________ > Virtualization mailing list > Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx > https://lists.linux-foundation.org/mailman/listinfo/virtualization _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/virtualization