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