This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / xen / xenfb / xenfb.c
1 /*
2  * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
3  *
4  * Copyright (C) 2005-2006
5  *
6  *      Anthony Liguori <aliguori@us.ibm.com>
7  *
8  *  Based on linux/drivers/video/q40fb.c
9  *
10  *  This file is subject to the terms and conditions of the GNU General Public
11  *  License. See the file COPYING in the main directory of this archive for
12  *  more details.
13  */
14
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/fb.h>
18 #include <linux/module.h>
19 #include <linux/vmalloc.h>
20 #include <linux/mm.h>
21 #include <asm/hypervisor.h>
22 #include <xen/evtchn.h>
23 #include <xen/xenbus.h>
24 #include <linux/xenfb.h>
25 #include <linux/kthread.h>
26
27 #define XENFB_WIDTH 800
28 #define XENFB_HEIGHT 600
29 #define XENFB_DEPTH 32
30
31 static int xenfb_fps = 20;
32 static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
33
34 struct xenfb_mapping
35 {
36         struct list_head        next;
37         struct vm_area_struct   *vma;
38         atomic_t                map_refs;
39         int                     faults;
40         struct xenfb_info       *info;
41 };
42
43 struct xenfb_info
44 {
45         struct task_struct              *kthread;
46         wait_queue_head_t               wq;
47
48         unsigned char                   *fb;
49         struct fb_fix_screeninfo        *fix;
50         struct fb_var_screeninfo        *var;
51         struct fb_info                  *fb_info;
52         struct timer_list               refresh;
53         int                             dirty;
54         int                             y1, y2;
55         int                             x1, x2;
56
57         struct semaphore                mm_lock;
58         int                             nr_pages;
59         struct page                     **pages;
60         struct list_head                mappings;
61
62         unsigned                        evtchn;
63         int                             irq;
64         struct xenfb_page               *page;
65         unsigned long                   *mfns;
66         u32                             flags;
67 };
68
69 static void xenfb_do_update(struct xenfb_info *info,
70                             int x, int y, int w, int h)
71 {
72         union xenfb_out_event event;
73         __u32 prod;
74
75         event.type = XENFB_TYPE_UPDATE;
76         event.update.x = x;
77         event.update.y = y;
78         event.update.width = w;
79         event.update.height = h;
80
81         prod = info->page->out_prod;
82         if (prod - info->page->out_cons == XENFB_OUT_RING_LEN)
83                 return;         /* ring buffer full, event lost */
84         mb();                   /* ensure ring space available */
85         XENFB_OUT_RING_REF(info->page, prod) = event;
86         wmb();                  /* ensure ring contents visible */
87         info->page->out_prod = prod + 1;
88
89         notify_remote_via_evtchn(info->evtchn);
90 }
91
92 static int xenfb_queue_full(struct xenfb_info *info)
93 {
94         __u32 cons, prod;
95
96         prod = info->page->out_prod;
97         cons = info->page->out_cons;
98         return prod - cons == XENFB_OUT_RING_LEN;
99 }
100
101 static void xenfb_update_screen(struct xenfb_info *info)
102 {
103         int y1, y2, x1, x2;
104         struct list_head *item;
105         struct xenfb_mapping *map;
106
107         if (!(info->flags & XENFB_FLAG_UPDATE))
108                 return;
109         if (xenfb_queue_full(info))
110                 return;
111
112         y1 = info->y1;
113         y2 = info->y2;
114         x1 = info->x1;
115         x2 = info->x2;
116         info->y1 = info->y2 = info->x1 = info->x2 = 0;
117         down(&info->mm_lock);
118         list_for_each(item, &info->mappings) {
119                 map = list_entry(item, struct xenfb_mapping, next);
120                 if (!map->faults)
121                         continue;
122                 zap_page_range(map->vma, map->vma->vm_start,
123                                map->vma->vm_end - map->vma->vm_start, NULL);
124                 map->faults = 0;
125         }
126         up(&info->mm_lock);
127
128         xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
129 }
130
131 static int xenfb_thread(void *data)
132 {
133         struct xenfb_info *info = data;
134
135         for (;;) {
136                 if (kthread_should_stop())
137                         break;
138                 if (info->dirty) {
139                         info->dirty = 0;
140                         xenfb_update_screen(info);
141                 }
142                 wait_event_interruptible(info->wq,
143                         kthread_should_stop() || info->dirty);
144         }
145         return 0;
146 }
147
148 static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
149                            unsigned blue, unsigned transp,
150                            struct fb_info *info)
151 {
152         u32 v;
153
154         if (regno > info->cmap.len)
155                 return 1;
156
157         red   >>= (16 - info->var.red.length);
158         green >>= (16 - info->var.green.length);
159         blue  >>= (16 - info->var.blue.length);
160
161         v = (red << info->var.red.offset) |
162             (green << info->var.green.offset) |
163             (blue << info->var.blue.offset);
164
165         switch (info->var.bits_per_pixel) {
166         case 16:
167         case 24:
168         case 32:
169                 ((u32 *)info->pseudo_palette)[regno] = v;
170                 break;
171         }
172         
173         return 0;
174 }
175
176 static void xenfb_timer(unsigned long data)
177 {
178         struct xenfb_info *info = (struct xenfb_info *)data;
179         info->dirty = 1;
180         wake_up(&info->wq);
181 }
182
183 static void xenfb_refresh(struct xenfb_info *info,
184                           int x1, int y1, int w, int h)
185 {
186         int y2, x2;
187
188         y2 = y1 + h;
189         x2 = x1 + w;
190         if (info->y2 == 0) {
191                 info->y1 = y1;
192                 info->y2 = y2;
193         }
194         if (info->x2 == 0) {
195                 info->x1 = x1;
196                 info->x2 = x2;
197         }
198
199         if (info->y1 > y1)
200                 info->y1 = y1;
201         if (info->y2 < y2)
202                 info->y2 = y2;
203         if (info->x1 > x1)
204                 info->x1 = x1;
205         if (info->x2 < x2)
206                 info->x2 = x2;
207
208         if (timer_pending(&info->refresh))
209                 return;
210
211         mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
212 }
213
214 static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
215 {
216         struct xenfb_info *info = p->par;
217
218         cfb_fillrect(p, rect);
219         xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
220 }
221
222 static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
223 {
224         struct xenfb_info *info = p->par;
225
226         cfb_imageblit(p, image);
227         xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
228 }
229
230 static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
231 {
232         struct xenfb_info *info = p->par;
233
234         cfb_copyarea(p, area);
235         xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
236 }
237
238 static void xenfb_vm_open(struct vm_area_struct *vma)
239 {
240         struct xenfb_mapping *map = vma->vm_private_data;
241         atomic_inc(&map->map_refs);
242 }
243
244 static void xenfb_vm_close(struct vm_area_struct *vma)
245 {
246         struct xenfb_mapping *map = vma->vm_private_data;
247         struct xenfb_info *info = map->info;
248
249         down(&info->mm_lock);
250         if (atomic_dec_and_test(&map->map_refs)) {
251                 list_del(&map->next);
252                 kfree(map);
253         }
254         up(&info->mm_lock);
255 }
256
257 static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
258                                     unsigned long vaddr, int *type)
259 {
260         struct xenfb_mapping *map = vma->vm_private_data;
261         struct xenfb_info *info = map->info;
262         int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
263         struct page *page;
264         int y1, y2;
265
266         if (pgnr >= info->nr_pages)
267                 return NOPAGE_SIGBUS;
268
269         down(&info->mm_lock);
270         page = info->pages[pgnr];
271         get_page(page);
272         map->faults++;
273
274         y1 = pgnr * PAGE_SIZE / info->fix->line_length;
275         y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fix->line_length;
276         if (y2 > info->var->yres)
277                 y2 = info->var->yres;
278         xenfb_refresh(info, 0, y1, info->var->xres, y2 - y1);
279         up(&info->mm_lock);
280
281         if (type)
282                 *type = VM_FAULT_MINOR;
283
284         return page;
285 }
286
287 static struct vm_operations_struct xenfb_vm_ops = {
288         .open   = xenfb_vm_open,
289         .close  = xenfb_vm_close,
290         .nopage = xenfb_vm_nopage,
291 };
292
293 static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
294 {
295         struct xenfb_info *info = fb_info->par;
296         struct xenfb_mapping *map;
297         int ret;
298         int map_pages;
299
300         down(&info->mm_lock);
301
302         ret = -EINVAL;
303         if (!(vma->vm_flags & VM_WRITE))
304                 goto out;
305         if (!(vma->vm_flags & VM_SHARED))
306                 goto out;
307         if (vma->vm_pgoff != 0)
308                 goto out;
309
310         map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
311         if (map_pages > info->nr_pages)
312                 goto out;
313
314         ret = -ENOMEM;
315         map = kmalloc(sizeof(*map), GFP_KERNEL);
316         if (map == NULL)
317                 goto out;
318         memset(map, 0, sizeof(*map));
319
320         map->vma = vma;
321         map->faults = 0;
322         map->info = info;
323         atomic_set(&map->map_refs, 1);
324         list_add(&map->next, &info->mappings);
325         vma->vm_ops = &xenfb_vm_ops;
326         vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
327         vma->vm_private_data = map;
328         ret = 0;
329
330  out:
331         up(&info->mm_lock);
332         return ret;
333 }
334
335 static struct fb_ops xenfb_fb_ops = {
336         .owner          = THIS_MODULE,
337         .fb_setcolreg   = xenfb_setcolreg,
338         .fb_fillrect    = xenfb_fillrect,
339         .fb_copyarea    = xenfb_copyarea,
340         .fb_imageblit   = xenfb_imageblit,
341         .fb_mmap        = xenfb_mmap,
342 };
343
344 static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
345                                        struct pt_regs *regs)
346 {
347         struct xenfb_info *info = dev_id;
348         __u32 cons, prod;
349
350         prod = info->page->in_prod;
351         rmb();                  /* ensure we see ring contents up to prod */
352         for (cons = info->page->in_cons; cons != prod; cons++) {
353                 union xenfb_in_event *event;
354                 event = &XENFB_IN_RING_REF(info->page, cons);
355
356                 switch (event->type) {
357                 case XENFB_TYPE_SET_EVENTS:
358                         info->flags = event->set_events.flags;
359                         break;
360                 }
361         }
362         mb();                   /* ensure we're done with ring contents */
363         info->page->in_cons = cons;
364         notify_remote_via_evtchn(info->evtchn);
365
366         return IRQ_HANDLED;
367 }
368
369 static unsigned long vmalloc_to_mfn(void *address)
370 {
371         return pfn_to_mfn(vmalloc_to_pfn(address));
372         //return arbitrary_virt_to_machine(address) >> PAGE_SHIFT;
373 }
374
375 static struct xenfb_info *xenfb_info;
376
377 static int __init xenfb_probe(void)
378 {
379         struct xenfb_info *info;
380         int i, ret;
381         struct fb_info *fb_info;
382         struct evtchn_alloc_unbound alloc_unbound;
383         struct evtchn_close close;
384         struct xenbus_transaction xbt;
385
386         /* Nothing to do if running in dom0. */
387         if (is_initial_xendomain())
388                 return -ENODEV;
389 #if 1
390         /* if we're not set up to use graphics mode, then don't initialize */
391         if (xenbus_scanf(XBT_NIL, "console", "use_graphics", "%d", &ret) < 0)
392                 return -ENODEV;
393         if (ret == 0)
394                 return -ENODEV;
395 #endif
396
397         info = kmalloc(sizeof(*info), GFP_KERNEL);
398         if (info == NULL)
399                 return -ENOMEM;
400         memset(info, 0, sizeof(*info));
401
402         INIT_LIST_HEAD(&info->mappings);
403
404         info->fb = vmalloc(xenfb_mem_len);
405         if (info->fb == NULL)
406                 goto error;
407         memset(info->fb, 0, xenfb_mem_len);
408         info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
409         info->pages = kmalloc(sizeof(struct page*)*info->nr_pages, GFP_KERNEL);
410         if (info->pages == NULL)
411                 goto error_vfree;
412         for (i = 0; i < info->nr_pages; i++)
413                 info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
414
415         fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
416         // FIXME sizeof(struct xenfb_info)
417         if (fb_info == NULL)
418                 goto error_kfree;
419
420         info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
421         /* set up shared page */
422         info->page = (void *)__get_free_page(GFP_KERNEL);
423         if (!info->page)
424                 goto error_kfree;
425         /* set up event channel */
426         alloc_unbound.dom = DOMID_SELF;
427         alloc_unbound.remote_dom = 0;
428         ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
429                                           &alloc_unbound);
430         if (ret)
431                 goto error_freep;
432         info->evtchn = alloc_unbound.port;
433
434         for (i = 0; i < info->nr_pages; i++)
435                 info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
436         info->page->pd[0] = vmalloc_to_mfn(info->mfns);
437         info->page->pd[1] = 0;
438         info->page->width = XENFB_WIDTH;
439         info->page->height = XENFB_HEIGHT;
440         info->page->depth = XENFB_DEPTH;
441         info->page->line_length = (info->page->depth / 8) * info->page->width;
442         info->page->mem_length = xenfb_mem_len;
443         info->page->in_cons = info->page->in_prod = 0;
444         info->page->out_cons = info->page->out_prod = 0;
445
446         ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
447                                         0, "xenfb", info);
448         if (ret < 0) {
449                 close.port = info->evtchn;
450                 HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
451                 goto error_freep;
452         }
453
454         info->irq = ret;
455         xenfb_info = info;
456
457         fb_info->pseudo_palette = fb_info->par;
458         fb_info->par = info;
459         fb_info->screen_base = info->fb;
460
461         memset(&fb_info->var, 0, sizeof(fb_info->var));
462         memset(&fb_info->fix, 0, sizeof(fb_info->fix));
463
464         fb_info->fbops = &xenfb_fb_ops;
465         fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
466         fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
467         fb_info->var.bits_per_pixel = info->page->depth;
468
469         fb_info->var.red = (struct fb_bitfield){16, 8, 0};
470         fb_info->var.green = (struct fb_bitfield){8, 8, 0};
471         fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
472
473         fb_info->var.activate = FB_ACTIVATE_NOW;
474         fb_info->var.height = -1;
475         fb_info->var.width = -1;
476         fb_info->var.vmode = FB_VMODE_NONINTERLACED;
477
478         fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
479         fb_info->fix.line_length = info->page->line_length;
480         fb_info->fix.smem_start = 0;
481         fb_info->fix.smem_len = xenfb_mem_len;
482         strcpy(fb_info->fix.id, "xen");
483         fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
484         fb_info->fix.accel = FB_ACCEL_NONE;
485
486         fb_info->flags = FBINFO_FLAG_DEFAULT;
487
488         fb_alloc_cmap(&fb_info->cmap, 256, 0);
489
490         info->fb_info = fb_info;
491         info->fix = &fb_info->fix;
492         info->var = &fb_info->var;
493
494         init_MUTEX(&info->mm_lock);
495         init_waitqueue_head(&info->wq);
496         init_timer(&info->refresh);
497         info->refresh.function = xenfb_timer;
498         info->refresh.data = (unsigned long)info;
499
500         info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
501         if (IS_ERR(info->kthread))
502                 goto error_unbind;
503
504         ret = register_framebuffer(fb_info);
505         if (ret)
506                 goto error_unbind;
507
508  again:
509         ret = xenbus_transaction_start(&xbt);
510         if (ret)
511                 goto error_unreg;
512         ret = xenbus_printf(xbt, "vfb", "page-ref", "%lu",
513                             virt_to_mfn(info->page));
514         // FIXME grant tables?
515         if (ret)
516                 goto error_xenbus;
517         ret = xenbus_printf(xbt, "vfb", "event-channel", "%u",
518                             info->evtchn);
519         if (ret)
520                 goto error_xenbus;
521         ret = xenbus_transaction_end(xbt, 0);
522         if (ret) {
523                 if (ret == -EAGAIN)
524                         goto again;
525                 goto error_unreg;
526         }
527
528         return 0;
529
530  error_xenbus:
531         xenbus_transaction_end(xbt, 1);
532  error_unreg:
533         unregister_framebuffer(fb_info);
534  error_unbind:
535         unbind_from_irqhandler(info->irq, info);
536         // FIXME do we have to stop info->kthread?
537  error_freep:
538         free_page((unsigned long)info->page);
539  error_kfree:
540         kfree(info->pages);
541  error_vfree:
542         vfree(info->fb);
543  error:
544         kfree(info);
545         xenfb_info = NULL;
546
547         return -ENODEV;
548 }
549
550 static int __init xenfb_init(void)
551 {
552         return xenfb_probe();
553 }
554
555 static void __exit xenfb_cleanup(void)
556 {
557         struct xenfb_info *info = xenfb_info;
558
559         unregister_framebuffer(info->fb_info);
560         unbind_from_irqhandler(info->irq, info);
561         free_page((unsigned long)info->page);
562         kfree(info->pages);
563         vfree(info->fb);
564         kfree(info);
565         xenfb_info = NULL;
566 }
567
568 module_init(xenfb_init);
569 module_exit(xenfb_cleanup);
570
571 MODULE_LICENSE("GPL");