RE: [PATCH 02/02] virtio: Add virtio platform driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux