From: dongkyun.yun Date: Fri, 25 Nov 2011 11:02:26 +0000 (+0900) Subject: [Title] Add general purpose interface (virtio) X-Git-Tag: 2.2.1_release^2~182^2~29 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e0f51bb84de602f1b5421afff73d0d34b80fbcde;p=sdk%2Femulator%2Femulator-kernel.git [Title] Add general purpose interface (virtio) [Type] Enhancement [Module] // Module Name - (Main / Sub) [Priority] // Importance : Critical / Major / Minor [CQ#] // CQ Issue Number [Redmine#] // Redmine Isuue Number [Problem] // Problem Description [Cause] // Cause Description [Solution] // Solution Description [TestCase] // Executed the test-target (How to) --- diff --git a/arch/x86/configs/i386_emul_defconfig b/arch/x86/configs/i386_emul_defconfig index 1b0b5cc77c4e..8bd30019ebf4 100644 --- a/arch/x86/configs/i386_emul_defconfig +++ b/arch/x86/configs/i386_emul_defconfig @@ -2576,7 +2576,7 @@ CONFIG_VIRTUALIZATION=y # CONFIG_LGUEST is not set CONFIG_VIRTIO=y CONFIG_VIRTIO_RING=y -# CONFIG_VIRTIO_EXAMPLE=y +CONFIG_VIRTIO_GPI=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=y CONFIG_BINARY_PRINTF=y diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 8d088dd8b4c5..8acc821cc219 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -7,8 +7,8 @@ config VIRTIO_RING tristate depends on VIRTIO -config VIRTIO_EXAMPLE - tristate "Virtio example driver (EXPERIMENTAL)" +config VIRTIO_GPI + tristate "Virtio general purpose driver" select VIRTIO select VIRTIO_RING diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index f7955ce8721c..dd905f528e71 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_VIRTIO) += virtio.o obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o -obj-$(CONFIG_VIRTIO_EXAMPLE) += virtio_example.o +obj-$(CONFIG_VIRTIO_GPI) += virtio_gpi.o obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o diff --git a/drivers/virtio/virtio_example.c b/drivers/virtio/virtio_example.c deleted file mode 100644 index ff429324ca43..000000000000 --- a/drivers/virtio/virtio_example.c +++ /dev/null @@ -1,334 +0,0 @@ -/* Virtio example implementation - * - * Copyright 2011 Dongkyun Yun - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// include/linux/virtio_ids.h -#define VIRTIO_ID_EXAMPLE 10 /* virtio example */ -// include/linux/virtio_balloon.h -#define VIRTIO_EXAMPLE_F_MUST_TELL_HOST 0 - -#define DEVICE_NAME "virtexample" -#define DEVICE_MINOR_NUM 70 - -/* Define to use debugging checksums on transfers */ -#undef DEBUG_EXIO - -/* Enable debug messages. */ -#define VIRTIO_EX_DEBUG - -#if defined(VIRTIO_EX_DEBUG) -#define logout(fmt, ...) \ - printk(KERN_INFO "[virtio][%s][%d]" fmt, __func__, __LINE__, ##__VA_ARGS__) -#else -#define logout(fmt, ...) ((void)0) -#endif - -struct virtio_ex_data { - int pid; - - int w_buf_size; - char *w_buf; - - int r_buf_size; - char *r_buf; -}__packed; - -#define to_virtio_ex_data(a) ((struct virtio_ex_data *)(a)->private_data) - -static struct virtqueue *vq = NULL; - -static struct virtio_device_id id_table[] = { - { VIRTIO_ID_EXAMPLE, VIRTIO_DEV_ANY_ID }, - { 0 }, -}; - -/* This is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c with - * some modifications - */ -static struct scatterlist *vmalloc_to_sg(struct scatterlist *sg_list, - unsigned char *virt, unsigned int pages) -{ - struct page *pg; - - /* unaligned */ - BUG_ON((ulong)virt & ~PAGE_MASK); - - /* Fill with elements for the data */ - while (pages) { - pg = vmalloc_to_page(virt); - if (!pg) - goto err; - - sg_set_page(sg_list, pg, PAGE_SIZE, 0); - virt += PAGE_SIZE; - sg_list++; - pages--; - } - - return sg_list; - -err: - kfree(sg_list); - sg_list = NULL; - return NULL; -} - -static unsigned int put_data(struct virtio_ex_data *exdata) -{ - struct scatterlist *sg; - static struct scatterlist *sg_list = NULL; - unsigned int ret, count, i_page, o_page, sg_entries; - - ret = exdata->w_buf_size; - - o_page = (exdata->w_buf_size + PAGE_SIZE-1) >> PAGE_SHIFT; - i_page = (exdata->r_buf_size + PAGE_SIZE-1) >> PAGE_SHIFT; - if (!o_page) - o_page = 1; - if (!i_page) - i_page = 1; - - logout("add_buf(out:%d, in:%d) \n", o_page*PAGE_SIZE, i_page*PAGE_SIZE); - - sg_entries = o_page + i_page; - - sg_list = kcalloc(sg_entries, sizeof(struct scatterlist), GFP_KERNEL); - if (!sg_list) { - logout("kcalloc is fail "); - ret = -EIO; - goto out; - } - - sg_init_table(sg_list, sg_entries); - - sg = vmalloc_to_sg(sg_list, exdata->w_buf, o_page); - sg = vmalloc_to_sg(sg, exdata->r_buf, i_page); - if (!sg) { - logout("vmalloc_to_sq is fail "); - ret = -EIO; - goto out; - } - - /* Transfer data */ - if (vq->vq_ops->add_buf(vq, sg_list, o_page, i_page, (void *)1) >= 0) { - vq->vq_ops->kick(vq); - /* Chill out until it's done with the buffer. */ - while (!vq->vq_ops->get_buf(vq, &count)) - cpu_relax(); - } - -out: - if (sg_list){ - kfree(sg_list); - sg_list = NULL; - } - - return ret; -} - -static void free_buffer(struct virtio_ex_data *exdata) -{ - if (exdata->w_buf) { - exdata->w_buf_size = 0; - vfree(exdata->w_buf); - exdata->w_buf= NULL; - } - if (exdata->r_buf) { - exdata->r_buf_size = 0; - vfree(exdata->r_buf); - exdata->r_buf= NULL; - } -} -static int virtexample_open(struct inode *inode, struct file *file) -{ - struct virtio_ex_data *exdata = NULL; - - logout("\n"); - - exdata = kzalloc(sizeof(struct virtio_ex_data), GFP_KERNEL); - if (!exdata) - return -ENXIO; - - exdata->pid = pid_nr(task_pid(current)); - logout("pid %d \n", exdata->pid); - - file->private_data = exdata; - - return 0; -} - -static int log_dump(char *buffer, int size) -{ - int i; - unsigned char *ptr = (unsigned char*)buffer; - - logout("pid %d ", pid_nr(task_pid(current))); - - logout("buffer[%p] size[%d] ", buffer, size); - logout("DATA BEGIN -------------- "); - - for(i=0; i < size; i++){ - logout(" %d = %02x(%c) ", i, ptr[i], ptr[i]); - } - logout("DATA END -------------- "); - return 0; -} - -static ssize_t virtexample_write(struct file *filp, const char *buffer, - size_t count, loff_t * posp) -{ - struct virtio_ex_data *exdata = to_virtio_ex_data(filp); - ssize_t ret; - - logout("\n"); - - /* for now, just allow one buffer to write(). */ - if (exdata->w_buf) - return -EIO; - - exdata->w_buf_size = count; - exdata->w_buf = vmalloc(exdata->w_buf_size); - if (!exdata->w_buf) - return -ENOMEM; - - exdata->r_buf_size = count; - exdata->r_buf = vmalloc(exdata->r_buf_size); - if (!exdata->r_buf) - return -ENOMEM; - - if (copy_from_user(exdata->w_buf, buffer, exdata->w_buf_size)) - return -EINVAL; - - log_dump(exdata->w_buf, exdata->w_buf_size); - - put_data(exdata); - - log_dump(exdata->r_buf, exdata->r_buf_size); - - ret = exdata->w_buf_size; - - return ret; -} - -static int virtexample_release(struct inode *inode, struct file *file) -{ - struct virtio_ex_data *exdata = to_virtio_ex_data(file); - - logout("\n"); - - if (exdata) { - free_buffer(exdata); - } - - kfree(exdata); - return 0; -} - -static const struct file_operations virtexample_fops = { - .owner = THIS_MODULE, - .open = virtexample_open, - .write = virtexample_write, - .release = virtexample_release, -}; - -static struct miscdevice virtexample_dev = { - DEVICE_MINOR_NUM, - DEVICE_NAME, - &virtexample_fops -}; - -static int virtexample_probe(struct virtio_device *vdev) -{ - int ret; - - logout("\n"); - - /* We expect a single virtqueue. */ - vq = virtio_find_single_vq(vdev, NULL, "output"); - if (IS_ERR(vq)) - return PTR_ERR(vq); - - ret = misc_register(&virtexample_dev); - if (ret) { - printk(KERN_ERR "virtexample: cannot register virtexample_dev as misc"); - return -ENODEV; - } - - return 0; -} - -static void __devexit virtexample_remove(struct virtio_device *vdev) -{ - logout("\n"); - vdev->config->reset(vdev); - misc_deregister(&virtexample_dev); - vdev->config->del_vqs(vdev); -} - -static void virtexample_changed(struct virtio_device *vdev) -{ - logout("\n"); - //struct virtio_balloon *vb = vdev->priv; - //wake_up(&vb->config_change); -} - - -static unsigned int features[] = { VIRTIO_EXAMPLE_F_MUST_TELL_HOST }; - -static struct virtio_driver virtio_example = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), - .driver.name = KBUILD_MODNAME, - .driver.owner = THIS_MODULE, - .id_table = id_table, - .probe = virtexample_probe, - .remove = __devexit_p(virtexample_remove), - .config_changed = virtexample_changed, -}; - -static int __init init(void) -{ - logout("\n"); - return register_virtio_driver(&virtio_example); -} - -static void __exit fini(void) -{ - logout("\n"); - unregister_virtio_driver(&virtio_example); -} - -module_init(init); -module_exit(fini); - -MODULE_DEVICE_TABLE(virtio, id_table); -MODULE_DESCRIPTION("Virtio example driver"); -MODULE_LICENSE("GPL v2"); - diff --git a/drivers/virtio/virtio_gpi.c b/drivers/virtio/virtio_gpi.c new file mode 100644 index 000000000000..7a443104cb06 --- /dev/null +++ b/drivers/virtio/virtio_gpi.c @@ -0,0 +1,334 @@ +/* Virtio general purpose interface implementation + * + * Copyright 2011 Dongkyun Yun + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* include/linux/virtio_balloon.h */ +#define VIRTIO_GPI_F_MUST_TELL_HOST 0 + +#define DEVICE_NAME "virt_gpi" +#define DEVICE_MINOR_NUM 70 + +/* Define to use debugging checksums on transfers */ +#undef DEBUG_EXIO + +/* Enable debug messages. */ +#define VIRTIO_GPI_DEBUG + +#if defined(VIRTIO_GPI_DEBUG) +#define logout(fmt, ...) \ + printk(KERN_INFO "[virt_gpi][%s][%d]" fmt, __func__, __LINE__, ##__VA_ARGS__) +#else +#define logout(fmt, ...) ((void)0) +#endif + +struct virtio_gpi_data { + int pid; + + int w_buf_size; + char *w_buf; + + int r_buf_size; + char *r_buf; +}__packed; + +#define to_virtio_gpi_data(a) ((struct virtio_gpi_data *)(a)->private_data) + +static struct virtqueue *vq = NULL; + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_GPI, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +/* This is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c with + * some modifications + */ +static struct scatterlist *vmalloc_to_sg(struct scatterlist *sg_list, + unsigned char *virt, unsigned int pages) +{ + struct page *pg; + + /* unaligned */ + BUG_ON((ulong)virt & ~PAGE_MASK); + + /* Fill with elements for the data */ + while (pages) { + pg = vmalloc_to_page(virt); + if (!pg) + goto err; + + sg_set_page(sg_list, pg, PAGE_SIZE, 0); + virt += PAGE_SIZE; + sg_list++; + pages--; + } + + return sg_list; + +err: + kfree(sg_list); + sg_list = NULL; + return NULL; +} + +static unsigned int put_data(struct virtio_gpi_data *exdata) +{ + struct scatterlist *sg; + static struct scatterlist *sg_list = NULL; + unsigned int ret, count, i_page, o_page, sg_entries; + + ret = exdata->w_buf_size; + + o_page = (exdata->w_buf_size + PAGE_SIZE-1) >> PAGE_SHIFT; + i_page = (exdata->r_buf_size + PAGE_SIZE-1) >> PAGE_SHIFT; + if (!o_page) + o_page = 1; + if (!i_page) + i_page = 1; + + logout("add_buf(out:%ld, in:%ld) \n", o_page*PAGE_SIZE, i_page*PAGE_SIZE); + + sg_entries = o_page + i_page; + + sg_list = kcalloc(sg_entries, sizeof(struct scatterlist), GFP_KERNEL); + if (!sg_list) { + logout("kcalloc is fail "); + ret = -EIO; + goto out; + } + + sg_init_table(sg_list, sg_entries); + + sg = vmalloc_to_sg(sg_list, exdata->w_buf, o_page); + sg = vmalloc_to_sg(sg, exdata->r_buf, i_page); + if (!sg) { + logout("vmalloc_to_sq is fail "); + ret = -EIO; + goto out; + } + + /* Transfer data */ + if (vq->vq_ops->add_buf(vq, sg_list, o_page, i_page, (void *)1) >= 0) { + vq->vq_ops->kick(vq); + /* Chill out until it's done with the buffer. */ + while (!vq->vq_ops->get_buf(vq, &count)) + cpu_relax(); + } + +out: + if (sg_list){ + kfree(sg_list); + sg_list = NULL; + } + + return ret; +} + +static void free_buffer(struct virtio_gpi_data *exdata) +{ + if (exdata->w_buf) { + exdata->w_buf_size = 0; + vfree(exdata->w_buf); + exdata->w_buf= NULL; + } + if (exdata->r_buf) { + exdata->r_buf_size = 0; + vfree(exdata->r_buf); + exdata->r_buf= NULL; + } +} +static int virt_gpi_open(struct inode *inode, struct file *file) +{ + struct virtio_gpi_data *exdata = NULL; + + logout("\n"); + + exdata = kzalloc(sizeof(struct virtio_gpi_data), GFP_KERNEL); + if (!exdata) + return -ENXIO; + + exdata->pid = pid_nr(task_pid(current)); + logout("pid %d \n", exdata->pid); + + file->private_data = exdata; + + return 0; +} + +static int log_dump(char *buffer, int size) +{ + int i; + unsigned char *ptr = (unsigned char*)buffer; + + logout("pid %d ", pid_nr(task_pid(current))); + + logout("buffer[%p] size[%d] ", buffer, size); + logout("DATA BEGIN -------------- "); + + for(i=0; i < size; i++){ + logout(" %d = %02x(%c) ", i, ptr[i], ptr[i]); + } + logout("DATA END -------------- "); + return 0; +} + +static ssize_t virt_gpi_write(struct file *filp, const char *buffer, + size_t count, loff_t * posp) +{ + struct virtio_gpi_data *exdata = to_virtio_gpi_data(filp); + ssize_t ret; + + logout("\n"); + + /* for now, just allow one buffer to write(). */ + if (exdata->w_buf) + return -EIO; + + exdata->w_buf_size = count; + exdata->w_buf = vmalloc(exdata->w_buf_size); + if (!exdata->w_buf) + return -ENOMEM; + + exdata->r_buf_size = count; + exdata->r_buf = vmalloc(exdata->r_buf_size); + if (!exdata->r_buf) + return -ENOMEM; + + if (copy_from_user(exdata->w_buf, buffer, exdata->w_buf_size)) + return -EINVAL; + + logout("ping-pong: write data \n"); + log_dump(exdata->w_buf, exdata->w_buf_size); + + put_data(exdata); + + logout("ping-pong: return data \n"); + log_dump(exdata->r_buf, exdata->r_buf_size); + + ret = exdata->w_buf_size; + + return ret; +} + +static int virt_gpi_release(struct inode *inode, struct file *file) +{ + struct virtio_gpi_data *exdata = to_virtio_gpi_data(file); + + logout("\n"); + + if (exdata) { + free_buffer(exdata); + } + + kfree(exdata); + return 0; +} + +static const struct file_operations virt_gpi_fops = { + .owner = THIS_MODULE, + .open = virt_gpi_open, + .write = virt_gpi_write, + .release = virt_gpi_release, +}; + +static struct miscdevice virt_gpi_dev = { + DEVICE_MINOR_NUM, + DEVICE_NAME, + &virt_gpi_fops +}; + +static int virt_gpi_probe(struct virtio_device *vdev) +{ + int ret; + + logout("\n"); + + /* We expect a single virtqueue. */ + vq = virtio_find_single_vq(vdev, NULL, "output"); + if (IS_ERR(vq)) + return PTR_ERR(vq); + + ret = misc_register(&virt_gpi_dev); + if (ret) { + printk(KERN_ERR "virt_gpi: cannot register virt_gpi_dev as misc"); + return -ENODEV; + } + + return 0; +} + +static void __devexit virt_gpi_remove(struct virtio_device *vdev) +{ + logout("\n"); + vdev->config->reset(vdev); + misc_deregister(&virt_gpi_dev); + vdev->config->del_vqs(vdev); +} + +static void virt_gpi_changed(struct virtio_device *vdev) +{ + logout("\n"); + //struct virtio_balloon *vb = vdev->priv; + //wake_up(&vb->config_change); +} + + +static unsigned int features[] = { VIRTIO_GPI_F_MUST_TELL_HOST }; + +static struct virtio_driver virtio_gpi = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virt_gpi_probe, + .remove = __devexit_p(virt_gpi_remove), + .config_changed = virt_gpi_changed, +}; + +static int __init init(void) +{ + logout("\n"); + return register_virtio_driver(&virtio_gpi); +} + +static void __exit fini(void) +{ + logout("\n"); + unregister_virtio_driver(&virtio_gpi); +} + +module_init(init); +module_exit(fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio general purpose driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h index 06660c0a78d7..e588758f1ace 100644 --- a/include/linux/virtio_ids.h +++ b/include/linux/virtio_ids.h @@ -13,5 +13,6 @@ #define VIRTIO_ID_RNG 4 /* virtio ring */ #define VIRTIO_ID_BALLOON 5 /* virtio balloon */ #define VIRTIO_ID_9P 9 /* 9p virtio console */ +#define VIRTIO_ID_GPI 20 /* virtio general purpose interface */ #endif /* _LINUX_VIRTIO_IDS_H */