[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <B8D6CA50DACE9E4AAADE9A4D56FBAAE6166661@039-SN1MPN1-004.039d.mgd.msft.net>
Date: Thu, 23 Jun 2011 08:54:06 +0000
From: Bhushan Bharat-R65777 <R65777@...escale.com>
To: Magnus Damm <magnus.damm@...il.com>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
CC: "vapier@...too.org" <vapier@...too.org>,
"mst@...hat.com" <mst@...hat.com>,
"linux-sh@...r.kernel.org" <linux-sh@...r.kernel.org>,
"virtualization@...ts.linux-foundation.org"
<virtualization@...ts.linux-foundation.org>
Subject: RE: [PATCH 02/02] virtio: Add virtio platform driver
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@...ts.linux-foundation.org
> [mailto:virtualization-bounces@...ts.linux-foundation.org] On Behalf Of
> Magnus Damm
> Sent: Tuesday, June 21, 2011 3:56 PM
> To: linux-kernel@...r.kernel.org
> Cc: vapier@...too.org; mst@...hat.com; linux-sh@...r.kernel.org; Magnus
> Damm; virtualization@...ts.linux-foundation.org
> Subject: [PATCH 02/02] virtio: Add virtio platform driver
>
> From: Magnus Damm <damm@...nsource.se>
>
> 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@...nsource.se>
> ---
>
> 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@...ts.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/virtualization
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists