]> git.pld-linux.org Git - packages/kernel.git/blob - kernel-virtio-gl-accel.patch
- 3.14.32
[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,315 @@
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 +       struct scatterlist *sgs[2];
180 +       sgs[0] = &sg_list[0];
181 +       sgs[1] = &sg_list[1];
182 +       if (virtqueue_add_sgs(vq, sgs, o_page, i_page, (void *)1, GFP_ATOMIC) >= 0) {
183 +               virtqueue_kick(vq);
184 +               /* Chill out until it's done with the buffer. */
185 +               while (!virtqueue_get_buf(vq, &count))
186 +                       cpu_relax();
187 +       }
188 +
189 +out_free:
190 +       kfree(sg_list);
191 +out:
192 +       return ret;
193 +}
194 +
195 +static void free_buffer(struct virtio_gl_data *gldata)
196 +{
197 +       if (gldata->buffer) {
198 +               vfree(gldata->buffer);
199 +               gldata->buffer = NULL;
200 +       }
201 +}
202 +
203 +static int glmem_open(struct inode *inode, struct file *file)
204 +{
205 +       struct virtio_gl_data *gldata = kzalloc(sizeof(struct virtio_gl_data),
206 +                                               GFP_KERNEL);
207 +
208 +       if (!gldata)
209 +               return -ENXIO;
210 +
211 +       gldata->pid = pid_nr(task_pid(current));
212 +
213 +       file->private_data = gldata;
214 +
215 +       return 0;
216 +}
217 +
218 +static int glmem_mmap(struct file *filp, struct vm_area_struct *vma)
219 +{
220 +       struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
221 +       int pages = (vma->vm_end - vma->vm_start) / PAGE_SIZE;
222 +
223 +       /* Set a reasonable limit */
224 +       if (pages > 16)
225 +               return -ENOMEM;
226 +
227 +       /* for now, just allow one buffer to be mmap()ed. */
228 +       if (gldata->buffer)
229 +               return -EIO;
230 +
231 +       gldata->buffer = vmalloc_user(pages*PAGE_SIZE);
232 +
233 +       if (!gldata->buffer)
234 +               return -ENOMEM;
235 +
236 +       gldata->pages = pages;
237 +
238 +       if (remap_vmalloc_range(vma, gldata->buffer, 0) < 0) {
239 +               vfree(gldata->buffer);
240 +               return -EIO;
241 +       }
242 +
243 +       vma->vm_flags |= VM_DONTEXPAND;
244 +
245 +       return 0;
246 +}
247 +
248 +static int glmem_fsync(struct file *filp, int datasync)
249 +{
250 +       struct virtio_gl_data *gldata = to_virtio_gl_data(filp);
251 +
252 +       put_data(gldata);
253 +
254 +       return 0;
255 +}
256 +
257 +static int glmem_release(struct inode *inode, struct file *file)
258 +{
259 +       struct virtio_gl_data *gldata = to_virtio_gl_data(file);
260 +
261 +       if (gldata && gldata->buffer) {
262 +               struct virtio_gl_header *header =
263 +                               (struct virtio_gl_header *)gldata->buffer;
264 +
265 +               /* Make sure the host hears about the process ending / dying */
266 +               header->pid = gldata->pid;
267 +               header->buf_size = SIZE_OUT_HEADER + 2;
268 +               header->r_buf_size = SIZE_IN_HEADER;
269 +               *(short *)(&header->buffer) = -1;
270 +
271 +               put_data(gldata);
272 +               free_buffer(gldata);
273 +       }
274 +
275 +       kfree(gldata);
276 +
277 +       return 0;
278 +}
279 +
280 +static const struct file_operations glmem_fops = {
281 +       .owner          = THIS_MODULE,
282 +       .open           = glmem_open,
283 +       .mmap           = glmem_mmap,
284 +       .fsync          = glmem_fsync,
285 +       .release        = glmem_release,
286 +};
287 +
288 +static struct miscdevice glmem_dev = {
289 +       MISC_DYNAMIC_MINOR,
290 +       DEVICE_NAME,
291 +       &glmem_fops
292 +};
293 +
294 +static int glmem_probe(struct virtio_device *vdev)
295 +{
296 +       int ret;
297 +
298 +       /* We expect a single virtqueue. */
299 +       vq = virtio_find_single_vq(vdev, NULL, "output");
300 +       if (IS_ERR(vq))
301 +               return PTR_ERR(vq);
302 +
303 +       ret = misc_register(&glmem_dev);
304 +       if (ret) {
305 +               printk(KERN_ERR "glmem: cannot register glmem_dev as misc");
306 +               return -ENODEV;
307 +       }
308 +
309 +       return 0;
310 +}
311 +
312 +static void glmem_remove(struct virtio_device *vdev)
313 +{
314 +       vdev->config->reset(vdev);
315 +       misc_deregister(&glmem_dev);
316 +       vdev->config->del_vqs(vdev);
317 +}
318 +
319 +static struct virtio_device_id id_table[] = {
320 +       { VIRTIO_ID_GL, VIRTIO_DEV_ANY_ID },
321 +       { 0 },
322 +};
323 +
324 +static struct virtio_driver virtio_gl_driver = {
325 +       .driver = {
326 +               .name =  KBUILD_MODNAME,
327 +               .owner = THIS_MODULE,
328 +       },
329 +       .id_table =     id_table,
330 +       .probe =        glmem_probe,
331 +       .remove =       glmem_remove,
332 +};
333 +
334 +static int __init glmem_init(void)
335 +{
336 +       return register_virtio_driver(&virtio_gl_driver);
337 +}
338 +
339 +static void __exit glmem_exit(void)
340 +{
341 +       unregister_virtio_driver(&virtio_gl_driver);
342 +}
343 +
344 +module_init(glmem_init);
345 +module_exit(glmem_exit);
346 +
347 +MODULE_DEVICE_TABLE(virtio, id_table);
348 +MODULE_DESCRIPTION("Virtio gl passthrough driver");
349 +MODULE_LICENSE("GPL v2");
350 +
351 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
352 index 3d94a14..9a9a6cc 100644
353 --- a/drivers/video/Kconfig
354 +++ b/drivers/video/Kconfig
355 @@ -16,6 +16,7 @@ source "drivers/char/agp/Kconfig"
356  source "drivers/gpu/vga/Kconfig"
357  
358  source "drivers/gpu/drm/Kconfig"
359 +source "drivers/gpu/misc/Kconfig"
360  
361  config VGASTATE
362         tristate
363 --- linux-3.4/include/uapi/linux/virtio_ids.h~  2012-05-21 08:42:02.000000000 +0200
364 +++ linux-3.4/include/uapi/linux/virtio_ids.h   2012-05-21 09:02:40.065957644 +0200
365 @@ -34,6 +34,7 @@
366  #define VIRTIO_ID_CONSOLE      3 /* virtio console */
367  #define VIRTIO_ID_RNG          4 /* virtio ring */
368  #define VIRTIO_ID_BALLOON      5 /* virtio balloon */
369 +#define VIRTIO_ID_GL           6 /* virtio usermem */
370  #define VIRTIO_ID_RPMSG                7 /* virtio remote processor messaging */
371  #define VIRTIO_ID_SCSI         8 /* virtio scsi */
372  #define VIRTIO_ID_9P           9 /* 9p virtio console */
373
This page took 0.081685 seconds and 3 git commands to generate.