]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-virtio-gl-accel.patch
- 3.1.101
[packages/kernel.git] / kernel-virtio-gl-accel.patch
1 M/
2 diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
3 index 30879df..35699a0 100644
4 --- a/drivers/gpu/Makefile
5 +++ b/drivers/gpu/Makefile
6 @@ -1 +1 @@
7 -obj-y                  += drm/ vga/
8 +obj-y                  += drm/ vga/ misc/
9 diff --git a/drivers/gpu/misc/Kconfig b/drivers/gpu/misc/Kconfig
10 new file mode 100644
11 index 0000000..50043d3
12 --- /dev/null
13 +++ b/drivers/gpu/misc/Kconfig
14 @@ -0,0 +1,8 @@
15 +config VIRTIOGL
16 +        tristate "Virtio userspace memory transport"
17 +        depends on VIRTIO_PCI
18 +        default n
19 +        help
20 +          A Driver to facilitate transferring data from userspace to a
21 +          hypervisor (eg. qemu)
22 +
23 diff --git a/drivers/gpu/misc/Makefile b/drivers/gpu/misc/Makefile
24 new file mode 100644
25 index 0000000..d9ab333
26 --- /dev/null
27 +++ b/drivers/gpu/misc/Makefile
28 @@ -0,0 +1 @@
29 +obj-$(CONFIG_VIRTIOGL)          += virtio-gl.o
30 diff --git a/drivers/gpu/misc/virtio-gl.c b/drivers/gpu/misc/virtio-gl.c
31 new file mode 100644
32 index 0000000..8882bda
33 --- /dev/null
34 +++ b/drivers/gpu/misc/virtio-gl.c
35 @@ -0,0 +1,312 @@
36 +/*
37 + * Copyright (C) 2010 Intel Corporation
38 + *
39 + * Author: Ian Molton <ian.molton@collabora.co.uk>
40 + *
41 + * This program is free software; you can redistribute it and/or modify
42 + * it under the terms of the GNU General Public License as published by
43 + * the Free Software Foundation; either version 2 of the License, or
44 + * (at your option) any later version.
45 + *
46 + * This program is distributed in the hope that it will be useful,
47 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
48 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
49 + * GNU General Public License for more details.
50 + *
51 + * You should have received a copy of the GNU General Public License
52 + * along with this program; if not, write to the Free Software
53 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
54 + */
55 +
56 +#include <linux/kernel.h>
57 +#include <linux/module.h>
58 +#include <linux/fs.h>
59 +#include <linux/dma-mapping.h>
60 +#include <linux/sched.h>
61 +#include <linux/slab.h>
62 +#include <linux/miscdevice.h>
63 +#include <linux/virtio.h>
64 +#include <linux/virtio_ids.h>
65 +#include <linux/virtio_config.h>
66 +
67 +#define DEVICE_NAME "glmem"
68 +
69 +/* Define to use debugging checksums on transfers */
70 +#undef DEBUG_GLIO
71 +
72 +struct virtio_gl_data {
73 +       char *buffer;
74 +       int pages;
75 +       unsigned int pid;
76 +};
77 +
78 +struct virtio_gl_header {
79 +       int pid;
80 +       int buf_size;
81 +       int r_buf_size;
82 +#ifdef DEBUG_GLIO
83 +       int sum;
84 +#endif
85 +       char buffer;
86 +} __packed;
87 +
88 +#define to_virtio_gl_data(a)   ((struct virtio_gl_data *)(a)->private_data)
89 +
90 +#ifdef DEBUG_GLIO
91 +#define SIZE_OUT_HEADER (sizeof(int)*4)
92 +#define SIZE_IN_HEADER (sizeof(int)*2)
93 +#else
94 +#define SIZE_OUT_HEADER (sizeof(int)*3)
95 +#define SIZE_IN_HEADER sizeof(int)
96 +#endif
97 +
98 +static struct virtqueue *vq;
99 +
100 +
101 +/* This is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c with
102 + * some modifications
103 + */
104 +static struct scatterlist *vmalloc_to_sg(struct scatterlist *sg_list,
105 +                               unsigned char *virt, unsigned int pages)
106 +{
107 +       struct page *pg;
108 +
109 +       /* unaligned */
110 +       BUG_ON((ulong)virt & ~PAGE_MASK);
111 +
112 +       /* Fill with elements for the data */
113 +       while (pages) {
114 +               pg = vmalloc_to_page(virt);
115 +               if (!pg)
116 +                       goto err;
117 +
118 +               sg_set_page(sg_list, pg, PAGE_SIZE, 0);
119 +               virt += PAGE_SIZE;
120 +               sg_list++;
121 +               pages--;
122 +       }
123 +
124 +       return sg_list;
125 +
126 +err:
127 +       kfree(sg_list);
128 +       return NULL;
129 +}
130 +
131 +static int put_data(struct virtio_gl_data *gldata)
132 +{
133 +       struct scatterlist *sg, *sg_list;
134 +       unsigned int count, ret, o_page, i_page, sg_entries;
135 +       struct virtio_gl_header *header =
136 +                               (struct virtio_gl_header *)gldata->buffer;
137 +
138 +       ret = header->buf_size;
139 +
140 +       o_page = (header->buf_size + PAGE_SIZE-1) >> PAGE_SHIFT;
141 +       i_page = (header->r_buf_size + PAGE_SIZE-1) >> PAGE_SHIFT;
142 +
143 +       header->pid = gldata->pid;
144 +
145 +       if ((o_page && i_page) &&
146 +               (o_page > gldata->pages || i_page > gldata->pages)) {
147 +               i_page = 0;
148 +       }
149 +
150 +       if (o_page > gldata->pages)
151 +               o_page = gldata->pages;
152 +
153 +       if (i_page > gldata->pages)
154 +               i_page = gldata->pages;
155 +
156 +       if (!o_page)
157 +               o_page = 1;
158 +
159 +       sg_entries = o_page + i_page;
160 +
161 +       sg_list = kcalloc(sg_entries, sizeof(struct scatterlist), GFP_KERNEL);
162 +
163 +       if (!sg_list) {
164 +               ret = -EIO;
165 +               goto out;
166 +       }
167 +
168 +       sg_init_table(sg_list, sg_entries);
169 +
170 +       sg = vmalloc_to_sg(sg_list, gldata->buffer, o_page);
171 +       sg = vmalloc_to_sg(sg, gldata->buffer, i_page);
172 +
173 +       if (!sg) {
174 +               ret = -EIO;
175 +               goto out_free;
176 +       }
177 +
178 +       /* Transfer data */
179 +       if (virtqueue_add_buf(vq, sg_list, o_page, i_page, (void *)1, GFP_ATOMIC) >= 0) {
180 +               virtqueue_kick(vq);
181 +               /* Chill out until it's done with the buffer. */
182 +               while (!virtqueue_get_buf(vq, &count))
183 +                       cpu_relax();
184 +       }
185 +
186 +out_free:
187 +       kfree(sg_list);
188 +out:
189 +       return ret;
190 +}
191 +
192 +static void free_buffer(struct virtio_gl_data *gldata)
193 +{
194 +       if (gldata->buffer) {
195 +               vfree(gldata->buffer);
196 +               gldata->buffer = NULL;
197 +       }
198 +}
199 +
200 +static int glmem_open(struct inode *inode, struct file *file)
201 +{
202 +       struct virtio_gl_data *gldata = kzalloc(sizeof(struct virtio_gl_data),
203 +                                               GFP_KERNEL);
204 +
205 +       if (!gldata)
206 +               return -ENXIO;
207 +
208 +       gldata->pid = pid_nr(task_pid(current));
209 +
210 +       file->private_data = gldata;
211 +
212 +       return 0;
213 +}
214 +
215 +static int glmem_mmap(struct file *filp, struct vm_area_struct *vma)
216 +{
217 +       struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
218 +       int pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE;
219 +
220 +       /* Set a reasonable limit */
221 +       if (pages > 16)
222 +               return -ENOMEM;
223 +
224 +       /* for now, just allow one buffer to be mmap()ed. */
225 +       if (gldata->buffer)
226 +               return -EIO;
227 +
228 +       gldata->buffer = vmalloc_user(pages*PAGE_SIZE);
229 +
230 +       if (!gldata->buffer)
231 +               return -ENOMEM;
232 +
233 +       gldata->pages = pages;
234 +
235 +       if (remap_vmalloc_range(vma, gldata->buffer, 0) < 0) {
236 +               vfree(gldata->buffer);
237 +               return -EIO;
238 +       }
239 +
240 +       vma->vm_flags |= VM_DONTEXPAND;
241 +
242 +       return 0;
243 +}
244 +
245 +static int glmem_fsync(struct file *filp, int datasync)
246 +{
247 +       struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
248 +
249 +       put_data(gldata);
250 +
251 +       return 0;
252 +}
253 +
254 +static int glmem_release(struct inode *inode, struct file *file)
255 +{
256 +       struct virtio_gl_data *gldata = to_virtio_gl_data(file);
257 +
258 +       if (gldata && gldata->buffer) {
259 +               struct virtio_gl_header *header =
260 +                               (struct virtio_gl_header *)gldata->buffer;
261 +
262 +               /* Make sure the host hears about the process ending / dying */
263 +               header->pid = gldata->pid;
264 +               header->buf_size = SIZE_OUT_HEADER + 2;
265 +               header->r_buf_size = SIZE_IN_HEADER;
266 +               *(short *)(&header->buffer) = -1;
267 +
268 +               put_data(gldata);
269 +               free_buffer(gldata);
270 +       }
271 +
272 +       kfree(gldata);
273 +
274 +       return 0;
275 +}
276 +
277 +static const struct file_operations glmem_fops = {
278 +       .owner          = THIS_MODULE,
279 +       .open           = glmem_open,
280 +       .mmap           = glmem_mmap,
281 +       .fsync          = glmem_fsync,
282 +       .release        = glmem_release,
283 +};
284 +
285 +static struct miscdevice glmem_dev = {
286 +       MISC_DYNAMIC_MINOR,
287 +       DEVICE_NAME,
288 +       &glmem_fops
289 +};
290 +
291 +static int glmem_probe(struct virtio_device *vdev)
292 +{
293 +       int ret;
294 +
295 +       /* We expect a single virtqueue. */
296 +       vq = virtio_find_single_vq(vdev, NULL, "output");
297 +       if (IS_ERR(vq))
298 +               return PTR_ERR(vq);
299 +
300 +       ret = misc_register(&glmem_dev);
301 +       if (ret) {
302 +               printk(KERN_ERR "glmem: cannot register glmem_dev as misc");
303 +               return -ENODEV;
304 +       }
305 +
306 +       return 0;
307 +}
308 +
309 +static void glmem_remove(struct virtio_device *vdev)
310 +{
311 +       vdev->config->reset(vdev);
312 +       misc_deregister(&glmem_dev);
313 +       vdev->config->del_vqs(vdev);
314 +}
315 +
316 +static struct virtio_device_id id_table[] = {
317 +       { VIRTIO_ID_GL, VIRTIO_DEV_ANY_ID },
318 +       { 0 },
319 +};
320 +
321 +static struct virtio_driver virtio_gl_driver = {
322 +       .driver = {
323 +               .name =  KBUILD_MODNAME,
324 +               .owner = THIS_MODULE,
325 +       },
326 +       .id_table =     id_table,
327 +       .probe =        glmem_probe,
328 +       .remove =       glmem_remove,
329 +};
330 +
331 +static int __init glmem_init(void)
332 +{
333 +       return register_virtio_driver(&virtio_gl_driver);
334 +}
335 +
336 +static void __exit glmem_exit(void)
337 +{
338 +       unregister_virtio_driver(&virtio_gl_driver);
339 +}
340 +
341 +module_init(glmem_init);
342 +module_exit(glmem_exit);
343 +
344 +MODULE_DEVICE_TABLE(virtio, id_table);
345 +MODULE_DESCRIPTION("Virtio gl passthrough driver");
346 +MODULE_LICENSE("GPL v2");
347 +
348 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
349 index 3d94a14..9a9a6cc 100644
350 --- a/drivers/video/Kconfig
351 +++ b/drivers/video/Kconfig
352 @@ -16,6 +16,7 @@ source "drivers/char/agp/Kconfig"
353  source "drivers/gpu/vga/Kconfig"
354  
355  source "drivers/gpu/drm/Kconfig"
356 +source "drivers/gpu/misc/Kconfig"
357  
358  config VGASTATE
359         tristate
360 --- linux-3.4/include/uapi/linux/virtio_ids.h~  2012-05-21 08:42:02.000000000 +0200
361 +++ linux-3.4/include/uapi/linux/virtio_ids.h   2012-05-21 09:02:40.065957644 +0200
362 @@ -34,6 +34,7 @@
363  #define VIRTIO_ID_CONSOLE      3 /* virtio console */
364  #define VIRTIO_ID_RNG          4 /* virtio ring */
365  #define VIRTIO_ID_BALLOON      5 /* virtio balloon */
366 +#define VIRTIO_ID_GL           6 /* virtio usermem */
367  #define VIRTIO_ID_RPMSG                7 /* virtio remote processor messaging */
368  #define VIRTIO_ID_SCSI         8 /* virtio scsi */
369  #define VIRTIO_ID_9P           9 /* 9p virtio console */
370
This page took 0.046219 seconds and 3 git commands to generate.