2 * Xen para-virtual frame buffer device
4 * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
5 * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
7 * Based on linux/drivers/video/q40fb.c
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
17 * Switch to grant tables when they become capable of dealing with the
21 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23 #include <linux/console.h>
24 #include <linux/kernel.h>
25 #include <linux/errno.h>
27 #include <linux/module.h>
28 #include <linux/slab.h>
29 #include <linux/vmalloc.h>
32 #include <asm/xen/hypervisor.h>
35 #include <xen/events.h>
37 #include <xen/interface/io/fbif.h>
38 #include <xen/interface/io/protocols.h>
39 #include <xen/xenbus.h>
40 #include <xen/platform_pci.h>
44 struct fb_info
*fb_info
;
45 int x1
, y1
, x2
, y2
; /* dirty rectangle,
46 protected by dirty_lock */
47 spinlock_t dirty_lock
;
50 struct xenfb_page
*page
;
52 int update_wanted
; /* XENFB_TYPE_UPDATE wanted */
53 int feature_resize
; /* XENFB_TYPE_RESIZE ok */
54 struct xenfb_resize resize
; /* protected by resize_lock */
55 int resize_dpy
; /* ditto */
56 spinlock_t resize_lock
;
58 struct xenbus_device
*xbdev
;
61 #define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8)
63 enum { KPARAM_MEM
, KPARAM_WIDTH
, KPARAM_HEIGHT
, KPARAM_CNT
};
64 static int video
[KPARAM_CNT
] = { 2, XENFB_WIDTH
, XENFB_HEIGHT
};
65 module_param_array(video
, int, NULL
, 0);
66 MODULE_PARM_DESC(video
,
67 "Video memory size in MB, width, height in pixels (default 2,800,600)");
69 static void xenfb_make_preferred_console(void);
70 static void xenfb_remove(struct xenbus_device
*);
71 static void xenfb_init_shared_page(struct xenfb_info
*, struct fb_info
*);
72 static int xenfb_connect_backend(struct xenbus_device
*, struct xenfb_info
*);
73 static void xenfb_disconnect_backend(struct xenfb_info
*);
75 static void xenfb_send_event(struct xenfb_info
*info
,
76 union xenfb_out_event
*event
)
80 prod
= info
->page
->out_prod
;
81 /* caller ensures !xenfb_queue_full() */
82 mb(); /* ensure ring space available */
83 XENFB_OUT_RING_REF(info
->page
, prod
) = *event
;
84 wmb(); /* ensure ring contents visible */
85 info
->page
->out_prod
= prod
+ 1;
87 notify_remote_via_irq(info
->irq
);
90 static void xenfb_do_update(struct xenfb_info
*info
,
91 int x
, int y
, int w
, int h
)
93 union xenfb_out_event event
;
95 memset(&event
, 0, sizeof(event
));
96 event
.type
= XENFB_TYPE_UPDATE
;
99 event
.update
.width
= w
;
100 event
.update
.height
= h
;
102 /* caller ensures !xenfb_queue_full() */
103 xenfb_send_event(info
, &event
);
106 static void xenfb_do_resize(struct xenfb_info
*info
)
108 union xenfb_out_event event
;
110 memset(&event
, 0, sizeof(event
));
111 event
.resize
= info
->resize
;
113 /* caller ensures !xenfb_queue_full() */
114 xenfb_send_event(info
, &event
);
117 static int xenfb_queue_full(struct xenfb_info
*info
)
121 prod
= info
->page
->out_prod
;
122 cons
= info
->page
->out_cons
;
123 return prod
- cons
== XENFB_OUT_RING_LEN
;
126 static void xenfb_handle_resize_dpy(struct xenfb_info
*info
)
130 spin_lock_irqsave(&info
->resize_lock
, flags
);
131 if (info
->resize_dpy
) {
132 if (!xenfb_queue_full(info
)) {
133 info
->resize_dpy
= 0;
134 xenfb_do_resize(info
);
137 spin_unlock_irqrestore(&info
->resize_lock
, flags
);
140 static void xenfb_refresh(struct xenfb_info
*info
,
141 int x1
, int y1
, int w
, int h
)
147 xenfb_handle_resize_dpy(info
);
149 if (!info
->update_wanted
)
152 spin_lock_irqsave(&info
->dirty_lock
, flags
);
154 /* Combine with dirty rectangle: */
164 if (xenfb_queue_full(info
)) {
165 /* Can't send right now, stash it in the dirty rectangle */
170 spin_unlock_irqrestore(&info
->dirty_lock
, flags
);
174 /* Clear dirty rectangle: */
175 info
->x1
= info
->y1
= INT_MAX
;
176 info
->x2
= info
->y2
= 0;
178 spin_unlock_irqrestore(&info
->dirty_lock
, flags
);
180 if (x1
<= x2
&& y1
<= y2
)
181 xenfb_do_update(info
, x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
184 static void xenfb_deferred_io(struct fb_info
*fb_info
, struct list_head
*pagereflist
)
186 struct xenfb_info
*info
= fb_info
->par
;
187 struct fb_deferred_io_pageref
*pageref
;
188 unsigned long beg
, end
;
189 int y1
, y2
, miny
, maxy
;
193 list_for_each_entry(pageref
, pagereflist
, list
) {
194 beg
= pageref
->offset
;
195 end
= beg
+ PAGE_SIZE
- 1;
196 y1
= beg
/ fb_info
->fix
.line_length
;
197 y2
= end
/ fb_info
->fix
.line_length
;
198 if (y2
>= fb_info
->var
.yres
)
199 y2
= fb_info
->var
.yres
- 1;
205 xenfb_refresh(info
, 0, miny
, fb_info
->var
.xres
, maxy
- miny
+ 1);
208 static struct fb_deferred_io xenfb_defio
= {
210 .deferred_io
= xenfb_deferred_io
,
213 static int xenfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
214 unsigned blue
, unsigned transp
,
215 struct fb_info
*info
)
219 if (regno
> info
->cmap
.len
)
222 #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
223 red
= CNVT_TOHW(red
, info
->var
.red
.length
);
224 green
= CNVT_TOHW(green
, info
->var
.green
.length
);
225 blue
= CNVT_TOHW(blue
, info
->var
.blue
.length
);
228 v
= (red
<< info
->var
.red
.offset
) |
229 (green
<< info
->var
.green
.offset
) |
230 (blue
<< info
->var
.blue
.offset
);
232 switch (info
->var
.bits_per_pixel
) {
236 ((u32
*)info
->pseudo_palette
)[regno
] = v
;
244 xenfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
246 struct xenfb_info
*xenfb_info
;
247 int required_mem_len
;
249 xenfb_info
= info
->par
;
251 if (!xenfb_info
->feature_resize
) {
252 if (var
->xres
== video
[KPARAM_WIDTH
] &&
253 var
->yres
== video
[KPARAM_HEIGHT
] &&
254 var
->bits_per_pixel
== xenfb_info
->page
->depth
) {
260 /* Can't resize past initial width and height */
261 if (var
->xres
> video
[KPARAM_WIDTH
] || var
->yres
> video
[KPARAM_HEIGHT
])
264 required_mem_len
= var
->xres
* var
->yres
* xenfb_info
->page
->depth
/ 8;
265 if (var
->bits_per_pixel
== xenfb_info
->page
->depth
&&
266 var
->xres
<= info
->fix
.line_length
/ (XENFB_DEPTH
/ 8) &&
267 required_mem_len
<= info
->fix
.smem_len
) {
268 var
->xres_virtual
= var
->xres
;
269 var
->yres_virtual
= var
->yres
;
275 static int xenfb_set_par(struct fb_info
*info
)
277 struct xenfb_info
*xenfb_info
;
280 xenfb_info
= info
->par
;
282 spin_lock_irqsave(&xenfb_info
->resize_lock
, flags
);
283 xenfb_info
->resize
.type
= XENFB_TYPE_RESIZE
;
284 xenfb_info
->resize
.width
= info
->var
.xres
;
285 xenfb_info
->resize
.height
= info
->var
.yres
;
286 xenfb_info
->resize
.stride
= info
->fix
.line_length
;
287 xenfb_info
->resize
.depth
= info
->var
.bits_per_pixel
;
288 xenfb_info
->resize
.offset
= 0;
289 xenfb_info
->resize_dpy
= 1;
290 spin_unlock_irqrestore(&xenfb_info
->resize_lock
, flags
);
294 static void xenfb_defio_damage_range(struct fb_info
*info
, off_t off
, size_t len
)
296 struct xenfb_info
*xenfb_info
= info
->par
;
298 xenfb_refresh(xenfb_info
, 0, 0, xenfb_info
->page
->width
, xenfb_info
->page
->height
);
301 static void xenfb_defio_damage_area(struct fb_info
*info
, u32 x
, u32 y
,
302 u32 width
, u32 height
)
304 struct xenfb_info
*xenfb_info
= info
->par
;
306 xenfb_refresh(xenfb_info
, x
, y
, width
, height
);
309 FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(xenfb
,
310 xenfb_defio_damage_range
,
311 xenfb_defio_damage_area
)
313 static const struct fb_ops xenfb_fb_ops
= {
314 .owner
= THIS_MODULE
,
315 FB_DEFAULT_DEFERRED_OPS(xenfb
),
316 .fb_setcolreg
= xenfb_setcolreg
,
317 .fb_check_var
= xenfb_check_var
,
318 .fb_set_par
= xenfb_set_par
,
321 static irqreturn_t
xenfb_event_handler(int rq
, void *dev_id
)
324 * No in events recognized, simply ignore them all.
325 * If you need to recognize some, see xen-kbdfront's
326 * input_handler() for how to do that.
328 struct xenfb_info
*info
= dev_id
;
329 struct xenfb_page
*page
= info
->page
;
331 if (page
->in_cons
!= page
->in_prod
) {
332 info
->page
->in_cons
= info
->page
->in_prod
;
333 notify_remote_via_irq(info
->irq
);
336 /* Flush dirty rectangle: */
337 xenfb_refresh(info
, INT_MAX
, INT_MAX
, -INT_MAX
, -INT_MAX
);
342 static int xenfb_probe(struct xenbus_device
*dev
,
343 const struct xenbus_device_id
*id
)
345 struct xenfb_info
*info
;
346 struct fb_info
*fb_info
;
351 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
353 xenbus_dev_fatal(dev
, -ENOMEM
, "allocating info structure");
357 /* Limit kernel param videoram amount to what is in xenstore */
358 if (xenbus_scanf(XBT_NIL
, dev
->otherend
, "videoram", "%d", &val
) == 1) {
359 if (val
< video
[KPARAM_MEM
])
360 video
[KPARAM_MEM
] = val
;
363 video
[KPARAM_WIDTH
] = xenbus_read_unsigned(dev
->otherend
, "width",
364 video
[KPARAM_WIDTH
]);
365 video
[KPARAM_HEIGHT
] = xenbus_read_unsigned(dev
->otherend
, "height",
366 video
[KPARAM_HEIGHT
]);
368 /* If requested res does not fit in available memory, use default */
369 fb_size
= video
[KPARAM_MEM
] * 1024 * 1024;
370 if (video
[KPARAM_WIDTH
] * video
[KPARAM_HEIGHT
] * XENFB_DEPTH
/ 8
372 pr_warn("display parameters %d,%d,%d invalid, use defaults\n",
373 video
[KPARAM_MEM
], video
[KPARAM_WIDTH
],
374 video
[KPARAM_HEIGHT
]);
375 video
[KPARAM_WIDTH
] = XENFB_WIDTH
;
376 video
[KPARAM_HEIGHT
] = XENFB_HEIGHT
;
377 fb_size
= XENFB_DEFAULT_FB_LEN
;
380 dev_set_drvdata(&dev
->dev
, info
);
383 info
->x1
= info
->y1
= INT_MAX
;
384 spin_lock_init(&info
->dirty_lock
);
385 spin_lock_init(&info
->resize_lock
);
387 info
->fb
= vzalloc(fb_size
);
388 if (info
->fb
== NULL
)
391 info
->nr_pages
= (fb_size
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
393 info
->gfns
= vmalloc(array_size(sizeof(unsigned long), info
->nr_pages
));
397 /* set up shared page */
398 info
->page
= (void *)__get_free_page(GFP_KERNEL
| __GFP_ZERO
);
402 /* abusing framebuffer_alloc() to allocate pseudo_palette */
403 fb_info
= framebuffer_alloc(sizeof(u32
) * 256, NULL
);
407 /* complete the abuse: */
408 fb_info
->pseudo_palette
= fb_info
->par
;
410 fb_info
->device
= &dev
->dev
;
412 fb_info
->screen_buffer
= info
->fb
;
414 fb_info
->fbops
= &xenfb_fb_ops
;
415 fb_info
->var
.xres_virtual
= fb_info
->var
.xres
= video
[KPARAM_WIDTH
];
416 fb_info
->var
.yres_virtual
= fb_info
->var
.yres
= video
[KPARAM_HEIGHT
];
417 fb_info
->var
.bits_per_pixel
= XENFB_DEPTH
;
419 fb_info
->var
.red
= (struct fb_bitfield
){16, 8, 0};
420 fb_info
->var
.green
= (struct fb_bitfield
){8, 8, 0};
421 fb_info
->var
.blue
= (struct fb_bitfield
){0, 8, 0};
423 fb_info
->var
.activate
= FB_ACTIVATE_NOW
;
424 fb_info
->var
.height
= -1;
425 fb_info
->var
.width
= -1;
426 fb_info
->var
.vmode
= FB_VMODE_NONINTERLACED
;
428 fb_info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
429 fb_info
->fix
.line_length
= fb_info
->var
.xres
* XENFB_DEPTH
/ 8;
430 fb_info
->fix
.smem_start
= 0;
431 fb_info
->fix
.smem_len
= fb_size
;
432 strcpy(fb_info
->fix
.id
, "xen");
433 fb_info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
434 fb_info
->fix
.accel
= FB_ACCEL_NONE
;
436 fb_info
->flags
= FBINFO_VIRTFB
;
438 ret
= fb_alloc_cmap(&fb_info
->cmap
, 256, 0);
440 framebuffer_release(fb_info
);
441 xenbus_dev_fatal(dev
, ret
, "fb_alloc_cmap");
445 fb_info
->fbdefio
= &xenfb_defio
;
446 fb_deferred_io_init(fb_info
);
448 xenfb_init_shared_page(info
, fb_info
);
450 ret
= xenfb_connect_backend(dev
, info
);
452 xenbus_dev_fatal(dev
, ret
, "xenfb_connect_backend");
456 ret
= register_framebuffer(fb_info
);
458 xenbus_dev_fatal(dev
, ret
, "register_framebuffer");
461 info
->fb_info
= fb_info
;
463 xenfb_make_preferred_console();
467 fb_deferred_io_cleanup(fb_info
);
468 fb_dealloc_cmap(&fb_info
->cmap
);
469 framebuffer_release(fb_info
);
473 xenbus_dev_fatal(dev
, ret
, "allocating device memory");
480 static void xenfb_make_preferred_console(void)
484 if (console_set_on_cmdline
)
488 for_each_console(c
) {
489 if (!strcmp(c
->name
, "tty") && c
->index
== 0)
493 console_force_preferred_locked(c
);
494 console_list_unlock();
497 static int xenfb_resume(struct xenbus_device
*dev
)
499 struct xenfb_info
*info
= dev_get_drvdata(&dev
->dev
);
501 xenfb_disconnect_backend(info
);
502 xenfb_init_shared_page(info
, info
->fb_info
);
503 return xenfb_connect_backend(dev
, info
);
506 static void xenfb_remove(struct xenbus_device
*dev
)
508 struct xenfb_info
*info
= dev_get_drvdata(&dev
->dev
);
510 xenfb_disconnect_backend(info
);
512 fb_deferred_io_cleanup(info
->fb_info
);
513 unregister_framebuffer(info
->fb_info
);
514 fb_dealloc_cmap(&info
->fb_info
->cmap
);
515 framebuffer_release(info
->fb_info
);
517 free_page((unsigned long)info
->page
);
523 static unsigned long vmalloc_to_gfn(void *address
)
525 return xen_page_to_gfn(vmalloc_to_page(address
));
528 static void xenfb_init_shared_page(struct xenfb_info
*info
,
529 struct fb_info
*fb_info
)
532 int epd
= PAGE_SIZE
/ sizeof(info
->gfns
[0]);
534 for (i
= 0; i
< info
->nr_pages
; i
++)
535 info
->gfns
[i
] = vmalloc_to_gfn(info
->fb
+ i
* PAGE_SIZE
);
537 for (i
= 0; i
* epd
< info
->nr_pages
; i
++)
538 info
->page
->pd
[i
] = vmalloc_to_gfn(&info
->gfns
[i
* epd
]);
540 info
->page
->width
= fb_info
->var
.xres
;
541 info
->page
->height
= fb_info
->var
.yres
;
542 info
->page
->depth
= fb_info
->var
.bits_per_pixel
;
543 info
->page
->line_length
= fb_info
->fix
.line_length
;
544 info
->page
->mem_length
= fb_info
->fix
.smem_len
;
545 info
->page
->in_cons
= info
->page
->in_prod
= 0;
546 info
->page
->out_cons
= info
->page
->out_prod
= 0;
549 static int xenfb_connect_backend(struct xenbus_device
*dev
,
550 struct xenfb_info
*info
)
552 int ret
, evtchn
, irq
;
553 struct xenbus_transaction xbt
;
555 ret
= xenbus_alloc_evtchn(dev
, &evtchn
);
558 irq
= bind_evtchn_to_irqhandler(evtchn
, xenfb_event_handler
,
559 0, dev
->devicetype
, info
);
561 xenbus_free_evtchn(dev
, evtchn
);
562 xenbus_dev_fatal(dev
, ret
, "bind_evtchn_to_irqhandler");
566 ret
= xenbus_transaction_start(&xbt
);
568 xenbus_dev_fatal(dev
, ret
, "starting transaction");
571 ret
= xenbus_printf(xbt
, dev
->nodename
, "page-ref", "%lu",
572 virt_to_gfn(info
->page
));
575 ret
= xenbus_printf(xbt
, dev
->nodename
, "event-channel", "%u",
579 ret
= xenbus_printf(xbt
, dev
->nodename
, "protocol", "%s",
580 XEN_IO_PROTO_ABI_NATIVE
);
583 ret
= xenbus_printf(xbt
, dev
->nodename
, "feature-update", "1");
586 ret
= xenbus_transaction_end(xbt
, 0);
590 xenbus_dev_fatal(dev
, ret
, "completing transaction");
594 xenbus_switch_state(dev
, XenbusStateInitialised
);
599 xenbus_transaction_end(xbt
, 1);
600 xenbus_dev_fatal(dev
, ret
, "writing xenstore");
602 unbind_from_irqhandler(irq
, info
);
606 static void xenfb_disconnect_backend(struct xenfb_info
*info
)
608 /* Prevent xenfb refresh */
609 info
->update_wanted
= 0;
611 unbind_from_irqhandler(info
->irq
, info
);
615 static void xenfb_backend_changed(struct xenbus_device
*dev
,
616 enum xenbus_state backend_state
)
618 struct xenfb_info
*info
= dev_get_drvdata(&dev
->dev
);
620 switch (backend_state
) {
621 case XenbusStateInitialising
:
622 case XenbusStateInitialised
:
623 case XenbusStateReconfiguring
:
624 case XenbusStateReconfigured
:
625 case XenbusStateUnknown
:
628 case XenbusStateInitWait
:
629 xenbus_switch_state(dev
, XenbusStateConnected
);
632 case XenbusStateConnected
:
634 * Work around xenbus race condition: If backend goes
635 * through InitWait to Connected fast enough, we can
636 * get Connected twice here.
638 if (dev
->state
!= XenbusStateConnected
)
639 /* no InitWait seen yet, fudge it */
640 xenbus_switch_state(dev
, XenbusStateConnected
);
642 if (xenbus_read_unsigned(info
->xbdev
->otherend
,
643 "request-update", 0))
644 info
->update_wanted
= 1;
646 info
->feature_resize
= xenbus_read_unsigned(dev
->otherend
,
647 "feature-resize", 0);
650 case XenbusStateClosed
:
651 if (dev
->state
== XenbusStateClosed
)
653 fallthrough
; /* Missed the backend's CLOSING state */
654 case XenbusStateClosing
:
655 xenbus_frontend_closed(dev
);
660 static const struct xenbus_device_id xenfb_ids
[] = {
665 static struct xenbus_driver xenfb_driver
= {
667 .probe
= xenfb_probe
,
668 .remove
= xenfb_remove
,
669 .resume
= xenfb_resume
,
670 .otherend_changed
= xenfb_backend_changed
,
671 .not_essential
= true,
674 static int __init
xenfb_init(void)
679 /* Nothing to do if running in dom0. */
680 if (xen_initial_domain())
683 if (!xen_has_pv_devices())
686 return xenbus_register_frontend(&xenfb_driver
);
689 static void __exit
xenfb_cleanup(void)
691 xenbus_unregister_driver(&xenfb_driver
);
694 module_init(xenfb_init
);
695 module_exit(xenfb_cleanup
);
697 MODULE_DESCRIPTION("Xen virtual framebuffer device frontend");
698 MODULE_LICENSE("GPL");
699 MODULE_ALIAS("xen:vfb");