[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel][PATCH][LINUX] Dynamic modes support for xenfb (2 of 2)
Markus Armbruster wrote: > Pat Campbell <plc@xxxxxxxxxx> writes: > > >> Markus Armbruster wrote: >> >>> Pat Campbell <plc@xxxxxxxxxx> writes: >>> >>> >>> >>>> Markus Armbruster wrote: >>>> >>>> >>>>> Pat Campbell <plc@xxxxxxxxxx> writes: >>>>> >>>>> >>>>> >>>>> >>>>>> Attached patch adds dynamic frame buffer resolution support to >>>>>> the PV xenfb frame buffer driver. >>>>>> >>>>>> Corresponding backend IOEMU patch is required for functionality but >>>>>> this patch is not dependent on it, preserving backwards compatibility. >>>>>> >>>>>> Please apply to tip of linux-2.6.18-xen >>>>>> >>>>>> Signed-off-by: Pat Campbell <plc@xxxxxxxxxx> >>>>>> >>>>>> >>>>>> >>>>> Adding another lock (queue_lock) to our already ticklish locking gives >>>>> me a queasy feeling... >>>>> >>>>> The purpose of the lock is not obvious to me. Please explain that, in >>>>> the code. Likewise, it's not entirely obvious that the locking works. >>>>> Please update the "How the locks work together" comment. >>>>> >>>>> But before you do that, I suggest you tell us exactly what problem >>>>> you're attempting to solve with queue_lock. Maybe we can come up with >>>>> a less scary solution. Maybe not. But it's worth a try. If it's >>>>> just to ensure the changes made by xenfb_set_par() are seen in >>>>> xenfb_do_resize() correctly, a memory barrier should to the trick more >>>>> easily. >>>>> >>>>> > [Pat explains the race...] > >>> Your race is real. >>> >>> Your old code shared the resolution state (info->resize_dpy and the >>> resolution variables in info->fb_info) between xenfb_do_resize() >>> (running in xenfb_thread) and xenfb_set_par() (running in another >>> thread). >>> >>> Your new code shares the ring buffer instead. >>> >>> Both methods can be made race-free with suitable synchronization. >>> >>> With your old code, xenfb_set_par() always succeeds. Until the >>> backend gets around to process the XENFB_TYPE_RESIZE message, it >>> interprets the frame buffer for the old resolution. As you argue >>> below, this isn't fatal, it can just mess up the display somewhat. >>> >>> With your new code, xenfb_set_par() can take a long time (one second), >>> and it can fail, leaving the display in a deranged state until the >>> next resolution change. It still doesn't fully synchronize with the >>> backend: it returns successfully after sending the message, leaving >>> the time window until the backend receives the message open. >>> >>> >> Synchronizing with the backend? I don't think this is necessary. The >> update events that follow the resize event will be for the new size, as >> long as the backend gets the resize event we should be ok. >> > > I didn't mean to say that synchronizing with the backend is necessary. > I just wanted to point out that your new method pays the price of > synchronization, namely a possibly significant delay in > xenfb_set_par(), plus an ugly failure mode there, without actually > achieving synchronization. > > >>> I'd prefer the old behavior. But I could be missing something here. >>> Am I? >>> >>> >>> >> I like the new behavior, it seems more straight forward and does not >> rely on the xenfb_thread() being active. Our first set_par() happens >> during frame buffer registration which is before xenfb_thread() is >> started. I disliked adding new code into the xenfb_update() function >> for an event that happens rarely so will revert back to the sharing of >> resize_dpy flag code. >> >> Is this how you envision xenfb_set_par() synchronization? >> >> static int xenfb_set_par(struct fb_info *info) >> { >> struct xenfb_info *xenfb_info; >> unsigned long flags; >> >> xenfb_info = info->par; >> >> if (xenfb_info->kthread) { >> spin_lock_irqsave(&xenfb_info->resize_lock, flags); >> info->var.xres_virtual = info->var.xres; >> info->var.yres_virtual = info->var.yres; >> xenfb_info->resize_dpy = 1; >> /* Wake up xenfb_thread() */ >> xenfb_refresh(xenfb_info, 0, 0, 1, 1); >> while (xenfb_info->kthread && xenfb_info->resize_dpy == 1) { >> msleep(10); >> } >> spin_unlock_irqrestore(&xenfb_info->resize_lock, flags); >> } >> return 0; >> } >> >> To explain the code a liitle bit. >> 1. Need to test for kthread because first xenfb_set_par() happens >> before xenfb_thread() is started >> > > Why can you just ignore the mode change then? > > >> 2. Need to wakeup xenfb_thread via refresh as application screen events >> are blocked waiting on the set_par to complete. Can't just set dirty, >> will get a bogus nasty gram. >> > > I'd pass an empty rectangle there: > > xenfb_refresh(xenfb_info, INT_MAX, INT_MAX, 0, 0); > > Alternatively, factor out the code to wake up the thread into a new > function, and call that here and from __xenfb_refresh(). That would > be cleaner. > > >> 3. Testing xenfb_thread in the while loop in case xenfb_remove() is >> called and thread is shutdown. Protects against a system shutdown >> hang. Don't know if that can happen, defensive code. >> > > Sleeps while holding a spinlock. Not good. And I didn't get the hang > you're trying to defend against. > > xenfb_resize_screen() still accesses the size unsynchronized, and can > thus see intermediate states of resolution changes. > > > No, that's not what I had in mind. Let me sketch it. > > The first question to answer for a mutex is: what shared state does it > protect? resize_lock protects the screen size fb_info->var.xres, > fb_info->var.yres and the flag resize_dpy. > > Once that's clear, the use of the mutex becomes obvious: wrap it > around any access of the shared state, i.e. the updating of the shared > state it protects in xenfb_set_par() and the reading in > xenfb_thread(). Code sketch: > > static void xenfb_resize_screen(struct xenfb_info *info) > { > if (xenfb_queue_full(info)) > return; > > /* caller holds info->resize_lock */ > info->resize_dpy = 0; > xenfb_do_resize(info); > } > > static int xenfb_thread(void *data) > { > struct xenfb_info *info = data; > unsigned long flags; > > while (!kthread_should_stop()) { > spin_lock_irqsave(info->resize_lock, flags); > if (info->resize_dpy) > xenfb_resize_screen(info); > spin_unlock_irqrestore(info->resize_lock, flags); > [...] > } > [...] > static int xenfb_set_par(struct fb_info *info) > { > struct xenfb_info *xenfb_info = info->par; > unsigned long flags; > > spin_lock_irqsave(info->resize_lock, flags); > info->var.xres_virtual = info->var.xres; > info->var.yres_virtual = info->var.yres; > xenfb_info->resize_dpy = 1; > spin_unlock_irqrestore(info->resize_lock, flags); > > if (xenfb_info->kthread) { > /* Wake up xenfb_thread() */ > xenfb_refresh(xenfb_info, INT_MAX, INT_MAX, 0, 0); > } > return 0; > } > > Note that xenfb_set_par() can schedule resolution changes just fine > before xenfb_thread() runs. It'll pick them up right when it starts. > > I used xenfb_refresh() to wake up xenfb_thread() only to keep things > simple, not to express a preference for that method. > > Don't just copy my code sketch! Review it carefully, please. > > >> ------------------- >> New lock comment >> >> /* >> * There are three locks: spinlock resize_lock protecting resize_dpy, >> > > It actually protects the screen size and resize_dpy. > > >> * spinlock dirty_lock protecting the dirty rectangle and mutex >> * mm_lock protecting mappings. >> * >> * resize_lock is used to synchronize resize_dpy access between >> * xenfb_set_par() and xenfb_do_resize() running in xenfb_thread(). >> * >> * How the dirty and mapping locks work together >> * >> .......... >> >> >> >>> I think you could fix the old code by protecting access to the shared >>> resolution state by a spin lock. >>> >>> If I am missing something, and your new code is the way to go, you >>> still need to migrate your explanation why it works from e-mail to >>> source file, where the poor maintainer can find it. >>> >>> [...] >>> >>> Looks like this is the last issue that you haven't addressed / >>> explained fully yet :) >>> >>> >>> >> Yahoo, getting close. Thanks >> >> Just an FYI, I am at Brainshare this week so my responses might be a >> little slow but I will try to turn around any comments I receive as soon >> as possible. Like to put this to bed before any more staging changes >> take place. >> > > Me too! And thanks for pushing this feature all the way. > > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxxxxxxxx > http://lists.xensource.com/xen-devel > I have attached front and back for your review. Back has not changed except to include opengl changes. Front has synchronization fix. I added a spin lock and struct xenfb_resize into struct xenfb. struct xenfb_resize was added to protect the screen size values from changes outside the driver. IE User application calls to ioctl(fb, FBIOPUT_VSCREENINFO, &fb_var); while the driver is processing a previous call. diff -r 76c9cf11ce23 tools/ioemu/hw/xenfb.c --- a/tools/ioemu/hw/xenfb.c Fri Mar 21 09:45:34 2008 +0000 +++ b/tools/ioemu/hw/xenfb.c Sun Mar 23 19:38:17 2008 -0600 @@ -516,6 +516,16 @@ static void xenfb_on_fb_event(struct xen } xenfb_guest_copy(xenfb, x, y, w, h); break; + case XENFB_TYPE_RESIZE: + xenfb->width = event->resize.width; + xenfb->height = event->resize.height; + xenfb->row_stride = event->resize.stride; + dpy_colourdepth(xenfb->ds, xenfb->depth); + dpy_resize(xenfb->ds, xenfb->width, xenfb->height, xenfb->row_stride); + if (xenfb->ds->shared_buf) + dpy_setdata(xenfb->ds, xenfb->pixels); + xenfb_invalidate(xenfb); + break; } } xen_mb(); /* ensure we're done with ring contents */ @@ -680,6 +690,7 @@ static int xenfb_read_frontend_fb_config static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) { struct xenfb_page *fb_page; int val; + int videoram; if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update", "%d", &val) < 0) @@ -702,10 +713,30 @@ static int xenfb_read_frontend_fb_config /* TODO check for consistency with the above */ xenfb->fb_len = fb_page->mem_length; xenfb->row_stride = fb_page->line_length; + + /* Protect against hostile frontend, limit fb_len to max allowed */ + if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.nodename, "videoram", "%d", + &videoram) < 0) + videoram = 0; + videoram = videoram * 1024 * 1024; + if (videoram && xenfb->fb_len > videoram) { + fprintf(stderr, "Framebuffer requested length of %zd exceeded allowed %d\n", + xenfb->fb_len, videoram); + xenfb->fb_len = videoram; + if (xenfb->row_stride * xenfb->height > xenfb->fb_len) + xenfb->height = xenfb->fb_len / xenfb->row_stride; + } fprintf(stderr, "Framebuffer depth %d width %d height %d line %d\n", fb_page->depth, fb_page->width, fb_page->height, fb_page->line_length); if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0) return -1; + + /* Indicate we have the frame buffer resize feature */ + xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1"); + + /* Tell kbd pointer the screen geometry */ + xenfb_xs_printf(xenfb->xsh, xenfb->kbd.nodename, "width", "%d", xenfb->width); + xenfb_xs_printf(xenfb->xsh, xenfb->kbd.nodename, "height", "%d", xenfb->height); if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) return -1; diff -r 76c9cf11ce23 tools/python/xen/xend/server/vfbif.py --- a/tools/python/xen/xend/server/vfbif.py Fri Mar 21 09:45:34 2008 +0000 +++ b/tools/python/xen/xend/server/vfbif.py Sun Mar 23 08:08:09 2008 -0600 @@ -6,7 +6,7 @@ import os import os CONFIG_ENTRIES = ['type', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused', - 'display', 'xauthority', 'keymap', + 'videoram', 'display', 'xauthority', 'keymap', 'uuid', 'location', 'protocol', 'opengl'] class VfbifController(DevController): diff -r 76c9cf11ce23 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Fri Mar 21 09:45:34 2008 +0000 +++ b/tools/python/xen/xm/create.py Sun Mar 23 08:10:23 2008 -0600 @@ -500,6 +500,11 @@ gopts.var('vncunused', val='', use="""Try to find an unused port for the VNC server. Only valid when vnc=1.""") +gopts.var('videoram', val='', + fn=set_value, default=None, + use="""Maximum amount of videoram PV guest can allocate + for frame buffer.""") + gopts.var('sdl', val='', fn=set_value, default=None, use="""Should the device model use SDL?""") @@ -645,7 +650,8 @@ def configure_vfbs(config_devs, vals): d['type'] = 'sdl' for (k,v) in d.iteritems(): if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display', - 'xauthority', 'type', 'vncpasswd', 'opengl' ]: + 'videoram', 'xauthority', 'type', 'vncpasswd', + 'opengl' ]: err("configuration option %s unknown to vfbs" % k) config.append([k,v]) if not d.has_key("keymap"): diff -r 76c9cf11ce23 xen/include/public/io/fbif.h --- a/xen/include/public/io/fbif.h Fri Mar 21 09:45:34 2008 +0000 +++ b/xen/include/public/io/fbif.h Sun Mar 23 08:05:53 2008 -0600 @@ -50,12 +50,28 @@ struct xenfb_update int32_t height; /* rect height */ }; +/* + * Framebuffer resize notification event + * Capable backend sets feature-resize in xenstore. + */ +#define XENFB_TYPE_RESIZE 3 + +struct xenfb_resize +{ + uint8_t type; /* XENFB_TYPE_RESIZE */ + int32_t width; /* width in pixels */ + int32_t height; /* height in pixels */ + int32_t stride; /* stride in bytes */ + int32_t depth; /* depth in bits */ +}; + #define XENFB_OUT_EVENT_SIZE 40 union xenfb_out_event { uint8_t type; struct xenfb_update update; + struct xenfb_resize resize; char pad[XENFB_OUT_EVENT_SIZE]; }; @@ -109,15 +125,17 @@ struct xenfb_page * Each directory page holds PAGE_SIZE / sizeof(*pd) * framebuffer pages, and can thus map up to PAGE_SIZE * * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and - * sizeof(unsigned long) == 4, that's 4 Megs. Two directory - * pages should be enough for a while. + * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs + * 64 bit. 256 directories give enough room for a 512 Meg + * framebuffer with a max resolution of 12,800x10,240. Should + * be enough for a while with room leftover for expansion. */ - unsigned long pd[2]; + unsigned long pd[256]; }; /* - * Wart: xenkbd needs to know resolution. Put it here until a better - * solution is found, but don't leak it to the backend. + * Wart: xenkbd needs to know default resolution. Put it here until a + * better solution is found, but don't leak it to the backend. */ #ifdef __KERNEL__ #define XENFB_WIDTH 800 diff -r de57c3f218fb drivers/xen/fbfront/xenfb.c --- a/drivers/xen/fbfront/xenfb.c Thu Mar 20 11:35:25 2008 +0000 +++ b/drivers/xen/fbfront/xenfb.c Sun Mar 23 19:52:17 2008 -0600 @@ -62,15 +62,21 @@ struct xenfb_info struct xenfb_page *page; unsigned long *mfns; int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + int feature_resize; /* Backend has resize feature */ + struct xenfb_resize resize; + int resize_dpy; + spinlock_t resize_lock; struct xenbus_device *xbdev; }; /* - * How the locks work together - * - * There are two locks: spinlock dirty_lock protecting the dirty - * rectangle, and mutex mm_lock protecting mappings. + * There are three locks: + * spinlock resize_lock protecting resize_dpy and screen size + * spinlock dirty_lock protecting the dirty rectangle + * mutex mm_lock protecting mappings. + * + * How the dirty and mapping locks work together * * The problem is that dirty rectangle and mappings aren't * independent: the dirty rectangle must cover all faulted pages in @@ -129,20 +135,41 @@ struct xenfb_info * * Oh well, we wont be updating the writes to this page anytime soon. */ +#define MB_ (1024*1024) +#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8) + +enum {KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT}; +static int video[KPARAM_CNT] = {2, XENFB_WIDTH, XENFB_HEIGHT}; +module_param_array(video, int, NULL, 0); +MODULE_PARM_DESC(video, + "Size of video memory in MB and width,height in pixels, default = (2,800,600)"); static int xenfb_fps = 20; -static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; static int xenfb_remove(struct xenbus_device *); -static void xenfb_init_shared_page(struct xenfb_info *); +static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *); static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); static void xenfb_disconnect_backend(struct xenfb_info *); +static void xenfb_send_event(struct xenfb_info *info, + union xenfb_out_event *event) +{ + __u32 prod; + + prod = info->page->out_prod; + /* caller ensures !xenfb_queue_full() */ + mb(); /* ensure ring space available */ + XENFB_OUT_RING_REF(info->page, prod) = *event; + wmb(); /* ensure ring contents visible */ + info->page->out_prod = prod + 1; + + notify_remote_via_irq(info->irq); +} + static void xenfb_do_update(struct xenfb_info *info, int x, int y, int w, int h) { union xenfb_out_event event; - __u32 prod; event.type = XENFB_TYPE_UPDATE; event.update.x = x; @@ -150,14 +177,22 @@ static void xenfb_do_update(struct xenfb event.update.width = w; event.update.height = h; - prod = info->page->out_prod; /* caller ensures !xenfb_queue_full() */ - mb(); /* ensure ring space available */ - XENFB_OUT_RING_REF(info->page, prod) = event; - wmb(); /* ensure ring contents visible */ - info->page->out_prod = prod + 1; - - notify_remote_via_irq(info->irq); + xenfb_send_event(info, &event); +} + +static void xenfb_do_resize(struct xenfb_info *info) +{ + union xenfb_out_event event; + + event.type = XENFB_TYPE_RESIZE; + event.resize.width = info->resize.width; + event.resize.height = info->resize.height; + event.resize.stride = info->resize.stride; + event.resize.depth = info->resize.depth; + + /* caller ensures !xenfb_queue_full() */ + xenfb_send_event(info, &event); } static int xenfb_queue_full(struct xenfb_info *info) @@ -209,11 +244,26 @@ static void xenfb_update_screen(struct x xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); } +static void xenfb_handle_resize_dpy(struct xenfb_info *info) +{ + int flags; + + spin_lock_irqsave(&info->resize_lock, flags); + if (info->resize_dpy) { + if (!xenfb_queue_full(info)) { + info->resize_dpy = 0; + xenfb_do_resize(info); + } + } + spin_unlock_irqrestore(&info->resize_lock, flags); +} + static int xenfb_thread(void *data) { struct xenfb_info *info = data; while (!kthread_should_stop()) { + xenfb_handle_resize_dpy(info); if (info->dirty) { info->dirty = 0; xenfb_update_screen(info); @@ -413,6 +463,55 @@ static int xenfb_mmap(struct fb_info *fb return 0; } +static int +xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct xenfb_info *xenfb_info; + int required_mem_len; + + xenfb_info = info->par; + + if (!xenfb_info->feature_resize) { + if (var->xres == video[KPARAM_WIDTH] && + var->yres == video[KPARAM_HEIGHT] && + var->bits_per_pixel == xenfb_info->page->depth) { + return 0; + } + return -EINVAL; + } + + /* Can't resize past initial width and height */ + if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT]) + return -EINVAL; + + required_mem_len = var->xres * var->yres * (xenfb_info->page->depth / 8); + if (var->bits_per_pixel == xenfb_info->page->depth && + var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) && + required_mem_len <= info->fix.smem_len) { + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + return 0; + } + return -EINVAL; +} + +static int xenfb_set_par(struct fb_info *info) +{ + struct xenfb_info *xenfb_info; + unsigned long flags; + + xenfb_info = info->par; + + spin_lock_irqsave(&xenfb_info->resize_lock, flags); + xenfb_info->resize.width = info->var.xres; + xenfb_info->resize.height = info->var.yres; + xenfb_info->resize.stride = info->fix.line_length; + xenfb_info->resize.depth = info->var.bits_per_pixel; + xenfb_info->resize_dpy = 1; + spin_unlock_irqrestore(&xenfb_info->resize_lock, flags); + return 0; +} + static struct fb_ops xenfb_fb_ops = { .owner = THIS_MODULE, .fb_setcolreg = xenfb_setcolreg, @@ -420,6 +519,8 @@ static struct fb_ops xenfb_fb_ops = { .fb_copyarea = xenfb_copyarea, .fb_imageblit = xenfb_imageblit, .fb_mmap = xenfb_mmap, + .fb_check_var = xenfb_check_var, + .fb_set_par = xenfb_set_par, }; static irqreturn_t xenfb_event_handler(int rq, void *dev_id, @@ -450,6 +551,8 @@ static int __devinit xenfb_probe(struct { struct xenfb_info *info; struct fb_info *fb_info; + int fb_size; + int val; int ret; info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -457,11 +560,27 @@ static int __devinit xenfb_probe(struct xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); return -ENOMEM; } + + /* Limit kernel param videoram amount to what is in xenstore */ + if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) { + if (val < video[KPARAM_MEM]) + video[KPARAM_MEM] = val; + } + + /* If requested res does not fit in available memory, use default */ + fb_size = video[KPARAM_MEM] * MB_; + if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH/8 > fb_size) { + video[KPARAM_WIDTH] = XENFB_WIDTH; + video[KPARAM_HEIGHT] = XENFB_HEIGHT; + fb_size = XENFB_DEFAULT_FB_LEN; + } + dev->dev.driver_data = info; info->xbdev = dev; info->irq = -1; info->x1 = info->y1 = INT_MAX; spin_lock_init(&info->dirty_lock); + spin_lock_init(&info->resize_lock); mutex_init(&info->mm_lock); init_waitqueue_head(&info->wq); init_timer(&info->refresh); @@ -469,12 +588,12 @@ static int __devinit xenfb_probe(struct info->refresh.data = (unsigned long)info; INIT_LIST_HEAD(&info->mappings); - info->fb = vmalloc(xenfb_mem_len); + info->fb = vmalloc(fb_size); if (info->fb == NULL) goto error_nomem; - memset(info->fb, 0, xenfb_mem_len); - - info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + memset(info->fb, 0, fb_size); + + info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; info->pages = kmalloc(sizeof(struct page *) * info->nr_pages, GFP_KERNEL); @@ -489,8 +608,6 @@ static int __devinit xenfb_probe(struct info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); if (!info->page) goto error_nomem; - - xenfb_init_shared_page(info); fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); /* see fishy hackery below */ @@ -504,9 +621,9 @@ static int __devinit xenfb_probe(struct fb_info->screen_base = info->fb; fb_info->fbops = &xenfb_fb_ops; - fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; - fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; - fb_info->var.bits_per_pixel = info->page->depth; + fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH]; + fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT]; + fb_info->var.bits_per_pixel = XENFB_DEPTH; fb_info->var.red = (struct fb_bitfield){16, 8, 0}; fb_info->var.green = (struct fb_bitfield){8, 8, 0}; @@ -518,9 +635,9 @@ static int __devinit xenfb_probe(struct fb_info->var.vmode = FB_VMODE_NONINTERLACED; fb_info->fix.visual = FB_VISUAL_TRUECOLOR; - fb_info->fix.line_length = info->page->line_length; + fb_info->fix.line_length = fb_info->var.xres * (XENFB_DEPTH / 8); fb_info->fix.smem_start = 0; - fb_info->fix.smem_len = xenfb_mem_len; + fb_info->fix.smem_len = fb_size; strcpy(fb_info->fix.id, "xen"); fb_info->fix.type = FB_TYPE_PACKED_PIXELS; fb_info->fix.accel = FB_ACCEL_NONE; @@ -533,6 +650,8 @@ static int __devinit xenfb_probe(struct xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); goto error; } + + xenfb_init_shared_page(info, fb_info); ret = register_framebuffer(fb_info); if (ret) { @@ -571,7 +690,7 @@ static int xenfb_resume(struct xenbus_de struct xenfb_info *info = dev->dev.driver_data; xenfb_disconnect_backend(info); - xenfb_init_shared_page(info); + xenfb_init_shared_page(info, info->fb_info); return xenfb_connect_backend(dev, info); } @@ -597,9 +716,11 @@ static int xenfb_remove(struct xenbus_de return 0; } -static void xenfb_init_shared_page(struct xenfb_info *info) +static void xenfb_init_shared_page(struct xenfb_info *info, + struct fb_info * fb_info) { int i; + int epd = PAGE_SIZE / sizeof(info->mfns[0]); for (i = 0; i < info->nr_pages; i++) info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE); @@ -607,13 +728,14 @@ static void xenfb_init_shared_page(struc for (i = 0; i < info->nr_pages; i++) info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); - info->page->pd[0] = vmalloc_to_mfn(info->mfns); - info->page->pd[1] = 0; - info->page->width = XENFB_WIDTH; - info->page->height = XENFB_HEIGHT; - info->page->depth = XENFB_DEPTH; - info->page->line_length = (info->page->depth / 8) * info->page->width; - info->page->mem_length = xenfb_mem_len; + for (i = 0; i * epd < info->nr_pages; i++) + info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); + + info->page->width = fb_info->var.xres; + info->page->height = fb_info->var.yres; + info->page->depth = fb_info->var.bits_per_pixel; + info->page->line_length = fb_info->fix.line_length; + info->page->mem_length = fb_info->fix.smem_len; info->page->in_cons = info->page->in_prod = 0; info->page->out_cons = info->page->out_prod = 0; } @@ -712,6 +834,11 @@ static void xenfb_backend_changed(struct val = 0; if (val) info->update_wanted = 1; + + if (xenbus_scanf(XBT_NIL, dev->otherend, + "feature-resize", "%d", &val) < 0) + val = 0; + info->feature_resize = val; break; case XenbusStateClosing: diff -r de57c3f218fb drivers/xen/fbfront/xenkbd.c --- a/drivers/xen/fbfront/xenkbd.c Thu Mar 20 11:35:25 2008 +0000 +++ b/drivers/xen/fbfront/xenkbd.c Sun Mar 23 08:04:40 2008 -0600 @@ -297,6 +297,16 @@ static void xenkbd_backend_changed(struc */ if (dev->state != XenbusStateConnected) goto InitWait; /* no InitWait seen yet, fudge it */ + + /* Set input abs params to match backend screen res */ + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "width", "%d", &val) > 0 ) + input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "height", "%d", &val) > 0 ) + input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); + break; case XenbusStateClosing: diff -r de57c3f218fb include/xen/interface/io/fbif.h --- a/include/xen/interface/io/fbif.h Thu Mar 20 11:35:25 2008 +0000 +++ b/include/xen/interface/io/fbif.h Sun Mar 23 08:04:40 2008 -0600 @@ -50,12 +50,28 @@ struct xenfb_update int32_t height; /* rect height */ }; +/* + * Framebuffer resize notification event + * Capable backend sets feature-resize in xenstore. + */ +#define XENFB_TYPE_RESIZE 3 + +struct xenfb_resize +{ + uint8_t type; /* XENFB_TYPE_RESIZE */ + int32_t width; /* width in pixels */ + int32_t height; /* height in pixels */ + int32_t stride; /* stride in bytes */ + int32_t depth; /* depth in bits */ +}; + #define XENFB_OUT_EVENT_SIZE 40 union xenfb_out_event { uint8_t type; struct xenfb_update update; + struct xenfb_resize resize; char pad[XENFB_OUT_EVENT_SIZE]; }; @@ -109,15 +125,17 @@ struct xenfb_page * Each directory page holds PAGE_SIZE / sizeof(*pd) * framebuffer pages, and can thus map up to PAGE_SIZE * * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and - * sizeof(unsigned long) == 4, that's 4 Megs. Two directory - * pages should be enough for a while. + * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs + * 64 bit. 256 directories give enough room for a 512 Meg + * framebuffer with a max resolution of 12,800x10,240. Should + * be enough for a while with room leftover for expansion. */ - unsigned long pd[2]; + unsigned long pd[256]; }; /* - * Wart: xenkbd needs to know resolution. Put it here until a better - * solution is found, but don't leak it to the backend. + * Wart: xenkbd needs to know default resolution. Put it here until a + * better solution is found, but don't leak it to the backend. */ #ifdef __KERNEL__ #define XENFB_WIDTH 800 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |