[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel][RFC] Dynamic modes support for PV xenfb (included)



Did everyone agree this version is good to go? I'll check it in if Dan and
Markus will ack it.

 -- Keir

On 28/1/08 00:48, "Pat Campbell" <plc@xxxxxxxxxx> wrote:

> Enough of the implementation has changed so I decided to go through
> another RFC cycle.
> 
> What this patch does
>    Allows PV framebuffer to be resized via xrandr or fbset and to start
>    up the GUI at higher than 800x600
> 
> What is new in this iteration:
>    1. No longer extending pd[] for extra memory
>    2. New kernel xenfb.videomem param
>    3. Added new events for extended FB memory mapping
>    4. Extending FB memory via gntdev, supports up to 20MB
>       on 64 bit guest, 40MB for a 32 bit guest.  Uses a two
>       level grant table.
>    5. xenkbd exported func to set pointer screen geometry
>    6. Removed "wart" from fbif.h
> 
> New kernel xenfb param:
>     videomem array,  FB size in MB, max scanline length
>     vm config ie:
>           extra="xenfb.videomem=5,1024 "
> 
> Setup instructions:
>  1. Apply xen-fbfront-resize.patch to the Xen 3.2 PV guest kernel source,
>     make and install
>  2. Add modes line to guest xorg.conf and adjust monitor section if
>     necessary
>  3. Add extra kernel param to guest config file and set into xenstore
>  4. Apply xen-fbback-resize.patch to xen-unstable tip, make and install
>     Really only need the new qemu-dm to be installed
> 
> Screen should start out at 800x600 in the console and then switch to
> whatever resolution you specified in xorg.conf for the GUI.  Switching
> to the console will revert screen to 800x600.
> 
> X11 fbdev will use the builtin resolution of 800x600 if alternate modes are
> not specified in xorg.conf.
> 
> xorg.conf settings I used:
> 
> Section "Monitor"
>   HorizSync    30-65
>   Identifier   "Monitor[0]"
>   ModelName    "XEN PV"
>   VendorName   "XEN"
>   VertRefresh  43-75
>   UseModes     "Modes[0]"
> EndSection
> 
> Section "Modes"
>   Identifier   "Modes[0]"
>   Modeline  "1024x768" 79.52 1024 1080 1192 1360 768 769 772 801
>   Modeline  "800x600" 47.53 800 840 920 1040 600 601 604 626
>   Modeline  "640x480" 29.84 640 664 728 816 480 481 484 501
> EndSection
> 
> Section "Screen"
>   SubSection "Display"
>     Depth      24
>     Modes      "1024x768" "800x600" "640x480"
>   EndSubSection
>   Device       "Device[0]"
>   Identifier   "Screen[0]"
>   Monitor      "Monitor[0]"
> EndSection
> 
> Will appreciate any feedback
> 
> Pat
> 
> diff -r 1c826ea72a80 tools/ioemu/hw/xenfb.c
> --- a/tools/ioemu/hw/xenfb.c Wed Jan 23 15:42:52 2008 +0000
> +++ b/tools/ioemu/hw/xenfb.c Thu Jan 24 08:26:55 2008 -0700
> @@ -8,6 +8,7 @@
>  #include <xen/io/fbif.h>
>  #include <xen/io/kbdif.h>
>  #include <xen/io/protocols.h>
> +#include <xen/grant_table.h>
>  #include <stdbool.h>
>  #include <xen/event_channel.h>
>  #include <sys/mman.h>
> @@ -45,6 +46,7 @@ struct xenfb {
> struct xs_handle *xsh; /* xs daemon handle */
> struct xenfb_device fb, kbd;
> void *pixels;           /* guest framebuffer data */
> + void *old_pixels;       /* guest FB data before remapping to extended */
> size_t fb_len;  /* size of framebuffer */
> int row_stride;         /* width of one row in framebuffer */
> int depth;              /* colour depth of guest framebuffer */
> @@ -52,7 +54,9 @@ struct xenfb {
> int height;             /* pixel height of guest framebuffer */
> int abs_pointer_wanted; /* Whether guest supports absolute pointer */
> int button_state;       /* Last seen pointer button state */
> - char protocol[64]; /* frontend protocol */
> + char protocol[64];      /* frontend protocol */
> + int otherend_bsize;     /* frontend bit size */
> + int gnttabdev; 
>  };
>  
>  /* Functions for frontend/backend state machine*/
> @@ -78,6 +82,8 @@ static void xenfb_invalidate(void *opaqu
>  static void xenfb_invalidate(void *opaque);
>  static void xenfb_screen_dump(void *opaque, const char *name);
>  static int xenfb_register_console(struct xenfb *xenfb);
> +static void xenfb_map_extended_fb(struct xenfb *xenfb, int, int, int);
> +static int xenfb_send_map_extended_done(struct xenfb *xenfb);
>  
>  /*
>   * Tables to map from scancode to Linux input layer keycode.
> @@ -261,9 +267,19 @@ struct xenfb *xenfb_new(int domid, Displ
> if (!xenfb->xsh)
> goto fail;
>  
> + xenfb->gnttabdev = xc_gnttab_open();
> + if (xenfb->gnttabdev == -1) {
> +  fprintf(stderr, "FB: Can't open gnttab device\n");
> + }
> +
> xenfb->ds = ds;
> xenfb_device_set_domain(&xenfb->fb, domid);
> xenfb_device_set_domain(&xenfb->kbd, domid);
> +
> + /* Indicate we have the frame buffer resize feature, requires grant tables
> */
> + if (xenfb->gnttabdev > 0) {
> +  xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1");
> + }
>  
> fprintf(stderr, "FB: Waiting for KBD backend creation\n");
> xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd);
> @@ -320,6 +336,58 @@ static void xenfb_copy_mfns(int mode, in
>  
> for (i = 0; i < count; i++)
> dst[i] = (mode == 32) ? src32[i] : src64[i];
> +}
> +
> +static void xenfb_map_extended_fb(struct xenfb *xenfb, int
> extended_mem_length,
> +  int gref_cnt, int gref)
> +{
> + int n_fbmfns;
> + unsigned long *fbmfns = NULL;
> + void *page; 
> + int i;
> + int ep_gref;
> + int amt;
> + int index;
> + void *pixels;
> + int *grefs;
> +
> + grefs = xc_gnttab_map_grant_ref (xenfb->gnttabdev,
> +   xenfb->fb.otherend_id,
> +   gref, 0);
> + if (NULL == grefs) {
> +  fprintf(stderr,"FB: Can't map to grant refs\n");
> +  return;
> + }
> + n_fbmfns = (extended_mem_length + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
> + fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
> + if (fbmfns) {
> +  ep_gref = PAGE_SIZE/(xenfb->otherend_bsize/8);
> +  amt = index = 0;
> +  for(i = 0; i < gref_cnt; i++) {
> +   page = xc_gnttab_map_grant_ref (xenfb->gnttabdev,
> +     xenfb->fb.otherend_id,
> +     grefs[i], 0);
> +   if (page) {
> +    index = i * ep_gref;
> +    amt = ep_gref;
> +    if (n_fbmfns - index < ep_gref)
> +     amt = n_fbmfns - index;
> +    xenfb_copy_mfns(xenfb->otherend_bsize, amt, &fbmfns[index], page);
> +    xc_gnttab_munmap(xenfb->gnttabdev, page, 1);
> +   }
> +   else
> +    goto gref_error;
> +  }
> +  pixels = xc_map_foreign_pages(xenfb->xc, xenfb->fb.otherend_id,
> +    PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
> +  if (pixels) {
> +   xenfb->old_pixels = xenfb->pixels;
> +   xenfb->pixels = pixels;
> +  }
> +  free(fbmfns);
> + }
> +gref_error:
> + xc_gnttab_munmap(xenfb->gnttabdev, grefs, 1);
>  }
>  
>  static int xenfb_map_fb(struct xenfb *xenfb, int domid)
> @@ -377,6 +445,7 @@ static int xenfb_map_fb(struct xenfb *xe
>  #endif
> }
>  
> + xenfb->otherend_bsize = mode;
> n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
> n_fbdirs = n_fbmfns * mode / 8;
> n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
> @@ -456,6 +525,10 @@ static void xenfb_detach_dom(struct xenf
> munmap(xenfb->pixels, xenfb->fb_len);
> xenfb->pixels = NULL;
> }
> + if (xenfb->old_pixels) {
> +  munmap(xenfb->old_pixels, xenfb->fb_len);
> +  xenfb->old_pixels = NULL;
> + }
>  }
>  
>  /* Remove the backend area in xenbus since the framebuffer really is
> @@ -473,6 +546,9 @@ void xenfb_shutdown(struct xenfb *xenfb)
> xc_evtchn_close(xenfb->evt_xch);
> if (xenfb->xsh)
> xs_daemon_close(xenfb->xsh);
> + if (xenfb->gnttabdev > 0)
> +  xc_gnttab_close(xenfb->gnttabdev);
> +
> free(xenfb);
>  }
>  
> @@ -510,6 +586,21 @@ 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_resize(xenfb->ds, xenfb->width, xenfb->height);
> +   break;
> +  case XENFB_TYPE_MAP_EXTENDED:
> +   if (xenfb->gnttabdev > 0) {
> +    xenfb_map_extended_fb(xenfb,
> +      event->map_extended.extended_mem_length,
> +      event->map_extended.gref_cnt,
> +      event->map_extended.gref);
> +   }
> +   xenfb_send_map_extended_done(xenfb);
> +   break;
> }
> }
> mb();   /* ensure we're done with ring contents */
> @@ -554,6 +645,41 @@ static int xenfb_on_state_change(struct
> }
> return 0;
>  }
> +
> +/* Send an event to the framebuffer frontend driver */
> +static int xenfb_fb_event(struct xenfb *xenfb,
> +  union xenfb_in_event *event)
> +{
> + uint32_t prod;
> + struct xenfb_page *page = xenfb->fb.page;
> +
> + if (xenfb->fb.state != XenbusStateConnected)
> +  return 0;
> +
> + prod = page->in_prod;
> + if (prod - page->in_cons == XENFB_IN_RING_LEN) {
> +  errno = EAGAIN;
> +  return -1;
> + }
> +
> + mb();   /* ensure ring space available */
> + XENFB_IN_RING_REF(page, prod) = *event;
> + wmb();   /* ensure ring contents visible */
> + page->in_prod = prod + 1;
> + return xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
> +}
> +
> +/* Send extended memory map done event to fb driver */
> +static int xenfb_send_map_extended_done(struct xenfb *xenfb)
> +{
> + union xenfb_in_event event;
> +
> + memset(&event, 0, XENFB_IN_EVENT_SIZE);
> + event.type = XENFB_TYPE_MAP_EXTENDED_DONE;
> +
> + return xenfb_fb_event(xenfb, &event);
> +}
> +
>  
>  /* Send an event to the keyboard frontend driver */
>  static int xenfb_kbd_event(struct xenfb *xenfb,
> diff -r 1c826ea72a80 xen/include/public/io/fbif.h
> --- a/xen/include/public/io/fbif.h Wed Jan 23 15:42:52 2008 +0000
> +++ b/xen/include/public/io/fbif.h Thu Jan 24 08:26:55 2008 -0700
> @@ -29,8 +29,9 @@
>  /* Out events (frontend -> backend) */
>  
>  /*
> - * Out events may be sent only when requested by backend, and receipt
> - * of an unknown out event is an error.
> + * Out event update is sent only when requested by backend
> + * Events resize and map_extended are frontend generated
> + * It is an error to send any unknown event types
>   */
>  
>  /* Event type 1 currently not used */
> @@ -50,12 +51,44 @@ 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;   /* future */
> +};
> +
> +/*
> + * Framebuffer map extended memory event
> + * Backend maps extended frame buffer memory
> + * for larger screen resolution support
> + */
> +#define XENFB_TYPE_MAP_EXTENDED 4
> +
> +struct xenfb_map_extended
> +{
> +    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED */
> +    int32_t extended_mem_length;    /* extended frame buffer len (in bytes)
> */
> +    int32_t gref_cnt;               /* number of mapping refernces used */
> +    int32_t gref;                   /* reference to mapping references */
> +};
> +
>  #define XENFB_OUT_EVENT_SIZE 40
>  
>  union xenfb_out_event
>  {
>      uint8_t type;
>      struct xenfb_update update;
> +    struct xenfb_resize resize;
> +    struct xenfb_map_extended map_extended;
>      char pad[XENFB_OUT_EVENT_SIZE];
>  };
>  
> @@ -63,14 +96,26 @@ union xenfb_out_event
>  
>  /*
>   * Frontends should ignore unknown in events.
> - * No in events currently defined.
>   */
> +
> +/*
> + * Framebuffer map extended memory done event
> + * Frontend ends foreign access to extended memory
> + * grant table references
> + */
> +#define XENFB_TYPE_MAP_EXTENDED_DONE 1
> +
> +struct xenfb_map_extended_done
> +{
> +    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED_DONE */
> +};
>  
>  #define XENFB_IN_EVENT_SIZE 40
>  
>  union xenfb_in_event
>  {
>      uint8_t type;
> +    struct xenfb_map_extended_done map_extended_done;
>      char pad[XENFB_IN_EVENT_SIZE];
>  };
>  
> @@ -115,16 +160,6 @@ struct xenfb_page
>      unsigned long pd[2];
>  };
>  
> -/*
> - * Wart: xenkbd needs to know resolution.  Put it here until a better
> - * solution is found, but don't leak it to the backend.
> - */
> -#ifdef __KERNEL__
> -#define XENFB_WIDTH 800
> -#define XENFB_HEIGHT 600
> -#define XENFB_DEPTH 32
> -#endif
> -
>  #endif
>  
>  /*
> diff -r 1c826ea72a80 xen/include/public/io/kbdif.h
> --- a/xen/include/public/io/kbdif.h Wed Jan 23 15:42:52 2008 +0000
> +++ b/xen/include/public/io/kbdif.h Thu Jan 24 08:26:55 2008 -0700
> @@ -119,6 +119,10 @@ struct xenkbd_page
>      uint32_t out_cons, out_prod;
>  };
>  
> +#ifdef __KERNEL__
> +void xenkbd_set_ptr_geometry(int xres, int yres);
> +#endif
> +
>  #endif
>  
>  /*
> diff -r 947e0701cf7a drivers/xen/fbfront/xenfb.c
> --- a/drivers/xen/fbfront/xenfb.c Tue Jan 22 21:52:44 2008 +0000
> +++ b/drivers/xen/fbfront/xenfb.c Thu Jan 24 08:27:06 2008 -0700
> @@ -27,7 +27,9 @@
>  #include <linux/mutex.h>
>  #include <asm/hypervisor.h>
>  #include <xen/evtchn.h>
> +#include <xen/gnttab.h>
>  #include <xen/interface/io/fbif.h>
> +#include <xen/interface/io/kbdif.h>
>  #include <xen/interface/io/protocols.h>
>  #include <xen/xenbus.h>
>  #include <linux/kthread.h>
> @@ -62,6 +64,18 @@ struct xenfb_info
> struct xenfb_page *page;
> unsigned long   *mfns;
> int   update_wanted; /* XENFB_TYPE_UPDATE wanted */
> + int   feature_resize; /* Backend has resize feature */
> + int   resize_dpy;
> + int   xres, yres;     /* current resolution */
> + int   fb_size;        /* fb size in bytes */
> + int   fb_width;       /* fb mem width in pixels */
> + int   fb_stride;      /* fb stride in bytes */
> + int   extended_mem;   /* fb is using extended mem */
> +
> + grant_ref_t gref_head;
> + uint32_t gref_cnt;          /* number of grant refernces used */
> + int * grefs;                /* references for mfns */
> + int gref;                   /* reference to mfn references */
>  
> struct xenbus_device *xbdev;
>  };
> @@ -129,20 +143,49 @@ struct xenfb_info
>   *
>   * Oh well, we wont be updating the writes to this page anytime soon.
>   */
> +static int videomem[2] = {0};
> +static int videomem_cnt = 0;
> +module_param_array(videomem, int, &videomem_cnt, 0);
> +MODULE_PARM_DESC(videomem,
> +  "Size of video memory in MB and width in pixels, default = (2,800)");
> +
> +#define XENFB_WIDTH 800
> +#define XENFB_HEIGHT 600
> +#define XENFB_DEPTH 32
> +#define MB_ (1024*1024)
> +#define XENFB_PIXCLOCK  9025  /* Xorg "1280x1024" 110.80 to FB 1000000/110.80
> */ 
> +#define XENFB_MAX_GREF_CNT  10   /* enough for 32 bit:41MB  64 bit:20MB
> extended frame buffer */
> +#define XENFB_MAX_FB_MEM (PAGE_SIZE/sizeof(long) * PAGE_SIZE *
> XENFB_MAX_GREF_CNT)
> +#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8)
>  
>  static int xenfb_fps = 20;
> -static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH
> / 8;
> +static unsigned long xenfb_mem_len = 0;
>  
>  static int xenfb_remove(struct xenbus_device *);
>  static void xenfb_init_shared_page(struct xenfb_info *);
>  static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info
> *);
>  static void xenfb_disconnect_backend(struct xenfb_info *);
> +static void xenfb_refresh(struct xenfb_info *info, int x1, int y1, int w, int
> h);
> +
> +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 +193,31 @@ 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->xres;
> + event.resize.height = info->yres;
> + event.resize.stride = info->fb_stride;
> +
> + xenfb_send_event(info, &event);
> +}
> +
> +static void xenfb_do_map_extended(struct xenfb_info *info)
> +{
> + union xenfb_out_event event;
> +
> + event.type = XENFB_TYPE_MAP_EXTENDED;
> + event.map_extended.extended_mem_length = info->fb_size;
> + event.map_extended.gref_cnt = info->gref_cnt;
> + event.map_extended.gref = info->gref;
> +
> + xenfb_send_event(info, &event);
>  }
>  
>  static int xenfb_queue_full(struct xenfb_info *info)
> @@ -209,6 +269,16 @@ static void xenfb_update_screen(struct x
> xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
>  }
>  
> +static void xenfb_resize_screen(struct xenfb_info *info)
> +{
> + if (xenfb_queue_full(info))
> +  return;
> +
> + info->resize_dpy = 0;
> + xenfb_do_resize(info);
> + xenfb_refresh(info, 0, 0, info->xres, info->yres);
> +}
> +
>  static int xenfb_thread(void *data)
>  {
> struct xenfb_info *info = data;
> @@ -217,6 +287,9 @@ static int xenfb_thread(void *data)
> if (info->dirty) {
> info->dirty = 0;
> xenfb_update_screen(info);
> +  }
> +  if (info->resize_dpy) {
> +   xenfb_resize_screen(info);
> }
> wait_event_interruptible(info->wq,
> kthread_should_stop() || info->dirty);
> @@ -413,6 +486,47 @@ 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;
> +
> + xenfb_info = info->par;
> +
> + if (!xenfb_info->feature_resize || !xenfb_info->extended_mem) {
> +  if (var->xres == XENFB_WIDTH && var->yres == XENFB_HEIGHT
> +    && var->bits_per_pixel == xenfb_info->page->depth) {
> +   return 0;
> +  }
> +  return -EINVAL;
> + }
> + if (var->bits_per_pixel == xenfb_info->page->depth &&
> +   xenfb_info->fb_width >= var->xres &&
> +   xenfb_mem_len >= (var->xres * var->yres * (xenfb_info->page->depth / 8)))
> {
> +  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;
> +
> + xenfb_info = info->par;
> +
> + if (xenfb_info->xres != info->var.xres ||
> +   xenfb_info->yres != info->var.yres) {
> +  xenfb_info->resize_dpy = 1;
> +  xenfb_info->xres = info->var.xres_virtual = info->var.xres;
> +  xenfb_info->yres = info->var.yres_virtual = info->var.yres;
> +  info->fix.line_length = xenfb_info->fb_stride;
> +  xenkbd_set_ptr_geometry(xenfb_info->xres, xenfb_info->yres);
> + }
> + return 0;
> +}
> +
>  static struct fb_ops xenfb_fb_ops = {
> .owner  = THIS_MODULE,
> .fb_setcolreg = xenfb_setcolreg,
> @@ -420,23 +534,47 @@ 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,
>       struct pt_regs *regs)
>  {
> - /*
> -  * No in events recognized, simply ignore them all.
> -  * If you need to recognize some, see xenbkd's input_handler()
> -  * for how to do that.
> -  */
> struct xenfb_info *info = dev_id;
> struct xenfb_page *page = info->page;
>  
> - if (page->in_cons != page->in_prod) {
> -  info->page->in_cons = info->page->in_prod;
> -  notify_remote_via_irq(info->irq);
> - }
> + __u32 cons, prod;
> + int i;
> +
> + prod = page->in_prod;
> + if (prod == page->out_cons)
> +  return IRQ_HANDLED;
> + rmb();   /* ensure we see ring contents up to prod */
> + for (cons = page->in_cons; cons != prod; cons++) {
> +  union xenfb_in_event *event;
> +  event = &XENFB_IN_RING_REF(page, cons);
> +
> +  switch (event->type) {
> +   case XENFB_TYPE_MAP_EXTENDED_DONE:
> +    gnttab_end_foreign_access_ref(info->gref);
> +    gnttab_release_grant_reference( &info->gref_head, info->gref);
> +
> +    for ( i = 0; i < info->gref_cnt; i++) {
> +     gnttab_end_foreign_access_ref(info->grefs[i]);
> +     gnttab_release_grant_reference( &info->gref_head, info->grefs[i]);
> +    }
> +                /* Map was being done during a resume, need to get the screen
> resized */
> +                if (info->xres != XENFB_WIDTH || info->yres != XENFB_HEIGHT)
> {
> +     info->resize_dpy = 1;
> +    }
> +    break;
> +  }
> + }
> + mb();   /* ensure we got ring contents */
> + page->in_cons = cons;
> + notify_remote_via_irq(info->irq);
> +
> return IRQ_HANDLED;
>  }
>  
> @@ -457,10 +595,24 @@ static int __devinit xenfb_probe(struct
> xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
> return -ENOMEM;
> }
> +
> + info->fb_size = XENFB_DEFAULT_FB_LEN;
> + info->fb_width = XENFB_WIDTH;
> + if (videomem_cnt == 2 && (videomem[0] * MB_) >= XENFB_DEFAULT_FB_LEN &&
> +   (videomem[0] * MB_) <= XENFB_MAX_FB_MEM &&
> +   videomem[1] >= XENFB_WIDTH) {
> +  info->fb_size = videomem[0] * MB_;
> +  info->fb_width = videomem[1];
> +  info->extended_mem = 1;
> + }
> + xenfb_mem_len = info->fb_size;
> +
> dev->dev.driver_data = info;
> info->xbdev = dev;
> info->irq = -1;
> info->x1 = info->y1 = INT_MAX;
> + info->xres = XENFB_WIDTH;
> + info->yres = XENFB_HEIGHT;
> spin_lock_init(&info->dirty_lock);
> mutex_init(&info->mm_lock);
> init_waitqueue_head(&info->wq);
> @@ -485,6 +637,11 @@ static int __devinit xenfb_probe(struct
> if (!info->mfns)
> goto error_nomem;
>  
> + info->grefs = vmalloc(sizeof(int) * (XENFB_MAX_GREF_CNT + 1));
> + if (!info->grefs)
> +  goto error_nomem;
> + memset(info->grefs, 0, sizeof(int) * (XENFB_MAX_GREF_CNT + 1));
> +
> /* set up shared page */
> info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
> if (!info->page)
> @@ -504,9 +661,10 @@ 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.xres_virtual = fb_info->var.xres = info->xres;
> + fb_info->var.yres_virtual = fb_info->var.yres = info->yres;
> fb_info->var.bits_per_pixel = info->page->depth;
> + fb_info->var.pixclock = XENFB_PIXCLOCK;
>  
> fb_info->var.red = (struct fb_bitfield){16, 8, 0};
> fb_info->var.green = (struct fb_bitfield){8, 8, 0};
> @@ -592,6 +750,7 @@ static int xenfb_remove(struct xenbus_de
> vfree(info->mfns);
> kfree(info->pages);
> vfree(info->fb);
> + vfree(info->grefs);
> kfree(info);
>  
> return 0;
> @@ -600,6 +759,7 @@ static void xenfb_init_shared_page(struc
>  static void xenfb_init_shared_page(struct xenfb_info *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);
> @@ -612,10 +772,32 @@ static void xenfb_init_shared_page(struc
> 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;
> + info->page->line_length = (info->page->depth / 8) * XENFB_WIDTH;
> + info->page->mem_length = XENFB_DEFAULT_FB_LEN;
> info->page->in_cons = info->page->in_prod = 0;
> info->page->out_cons = info->page->out_prod = 0;
> +
> + if (info->extended_mem) {
> +  info->fb_stride = (info->page->depth / 8) * info->fb_width;
> +  if (gnttab_alloc_grant_references(XENFB_MAX_GREF_CNT + 1, &info->gref_head)
> == 0) {
> +   info->gref = gnttab_claim_grant_reference(&info->gref_head);
> +   gnttab_grant_foreign_access_ref(
> +     info->gref,
> +     info->xbdev->otherend_id,
> +     vmalloc_to_mfn(info->grefs), 0);
> +   for (i = 0; i * epd < info->nr_pages; i++) {
> +    info->grefs[i] = gnttab_claim_grant_reference(&info->gref_head);
> +    gnttab_grant_foreign_access_ref( info->grefs[i],
> +      info->xbdev->otherend_id,
> +      vmalloc_to_mfn(&info->mfns[i * epd]), 0);
> +   }
> +   info->gref_cnt = i;
> +   gnttab_free_grant_references(info->gref_head);
> +  }
> +  if (!info->gref_cnt) {
> +   info->extended_mem = 0;
> +  }
> + }
>  }
>  
>  static int xenfb_connect_backend(struct xenbus_device *dev,
> @@ -710,6 +892,15 @@ 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;
> +
> +  if (info->feature_resize && info->extended_mem) {
> +   xenfb_do_map_extended(info);
> +  }
> break;
>  
> case XenbusStateClosing:
> @@ -744,6 +935,8 @@ static int __init xenfb_init(void)
> if (is_initial_xendomain())
> return -ENODEV;
>  
> + xenkbd_set_ptr_geometry(XENFB_WIDTH, XENFB_HEIGHT);
> +
> return xenbus_register_frontend(&xenfb);
>  }
>  
> diff -r 947e0701cf7a drivers/xen/fbfront/xenkbd.c
> --- a/drivers/xen/fbfront/xenkbd.c Tue Jan 22 21:52:44 2008 +0000
> +++ b/drivers/xen/fbfront/xenkbd.c Thu Jan 24 08:27:06 2008 -0700
> @@ -40,6 +40,10 @@ static int xenkbd_remove(struct xenbus_d
>  static int xenkbd_remove(struct xenbus_device *);
>  static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info
> *);
>  static void xenkbd_disconnect_backend(struct xenkbd_info *);
> +
> +static int max_abs_xres;
> +static int max_abs_yres;
> +static struct input_dev *mouse_ptr;
>  
>  /*
>   * Note: if you need to send out events, see xenfb_do_update() for how
> @@ -163,8 +167,8 @@ int __devinit xenkbd_probe(struct xenbus
> for (i = BTN_LEFT; i <= BTN_TASK; i++)
> set_bit(i, ptr->keybit);
> ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
> - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
> - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
> + input_set_abs_params(ptr, ABS_X, 0, max_abs_xres, 0, 0);
> + input_set_abs_params(ptr, ABS_Y, 0, max_abs_yres, 0, 0);
>  
> ret = input_register_device(ptr);
> if (ret) {
> @@ -172,7 +176,7 @@ int __devinit xenkbd_probe(struct xenbus
> xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
> goto error;
> }
> - info->ptr = ptr;
> + mouse_ptr = info->ptr = ptr;
>  
> ret = xenkbd_connect_backend(dev, info);
> if (ret < 0)
> @@ -338,6 +342,18 @@ static void __exit xenkbd_cleanup(void)
> return xenbus_unregister_driver(&xenkbd);
>  }
>  
> +void xenkbd_set_ptr_geometry(int xres, int yres)
> +{
> + max_abs_xres = xres;
> + max_abs_yres = yres;
> + if (mouse_ptr) {
> +  input_set_abs_params(mouse_ptr, ABS_X, 0, max_abs_xres, 0, 0);
> +  input_set_abs_params(mouse_ptr, ABS_Y, 0, max_abs_yres, 0, 0);
> +  input_event(mouse_ptr, EV_SYN, SYN_CONFIG, 0);
> + }
> +}
> +EXPORT_SYMBOL(xenkbd_set_ptr_geometry);
> +
>  module_init(xenkbd_init);
>  module_exit(xenkbd_cleanup);
>  
> diff -r 947e0701cf7a include/xen/interface/io/fbif.h
> --- a/include/xen/interface/io/fbif.h Tue Jan 22 21:52:44 2008 +0000
> +++ b/include/xen/interface/io/fbif.h Thu Jan 24 08:27:06 2008 -0700
> @@ -29,8 +29,9 @@
>  /* Out events (frontend -> backend) */
>  
>  /*
> - * Out events may be sent only when requested by backend, and receipt
> - * of an unknown out event is an error.
> + * Out event update is sent only when requested by backend
> + * Events resize and map_extended are frontend generated
> + * It is an error to send any unknown event types
>   */
>  
>  /* Event type 1 currently not used */
> @@ -50,12 +51,44 @@ 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;   /* future */
> +};
> +
> +/*
> + * Framebuffer map extended memory event
> + * Backend maps extended frame buffer memory
> + * for larger screen resolution support
> + */
> +#define XENFB_TYPE_MAP_EXTENDED 4
> +
> +struct xenfb_map_extended
> +{
> +    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED */
> +    int32_t extended_mem_length;    /* extended frame buffer len (in bytes)
> */
> +    int32_t gref_cnt;               /* number of mapping refernces used */
> +    int32_t gref;                   /* reference to mapping references */
> +};
> +
>  #define XENFB_OUT_EVENT_SIZE 40
>  
>  union xenfb_out_event
>  {
>      uint8_t type;
>      struct xenfb_update update;
> +    struct xenfb_resize resize;
> +    struct xenfb_map_extended map_extended;
>      char pad[XENFB_OUT_EVENT_SIZE];
>  };
>  
> @@ -63,14 +96,26 @@ union xenfb_out_event
>  
>  /*
>   * Frontends should ignore unknown in events.
> - * No in events currently defined.
>   */
> +
> +/*
> + * Framebuffer map extended memory done event
> + * Frontend ends foreign access to extended memory
> + * grant table references
> + */
> +#define XENFB_TYPE_MAP_EXTENDED_DONE 1
> +
> +struct xenfb_map_extended_done
> +{
> +    uint8_t type;                   /* XENFB_TYPE_MAP_EXTENDED_DONE */
> +};
>  
>  #define XENFB_IN_EVENT_SIZE 40
>  
>  union xenfb_in_event
>  {
>      uint8_t type;
> +    struct xenfb_map_extended_done map_extended_done;
>      char pad[XENFB_IN_EVENT_SIZE];
>  };
>  
> @@ -115,16 +160,6 @@ struct xenfb_page
>      unsigned long pd[2];
>  };
>  
> -/*
> - * Wart: xenkbd needs to know resolution.  Put it here until a better
> - * solution is found, but don't leak it to the backend.
> - */
> -#ifdef __KERNEL__
> -#define XENFB_WIDTH 800
> -#define XENFB_HEIGHT 600
> -#define XENFB_DEPTH 32
> -#endif
> -
>  #endif
>  
>  /*
> diff -r 947e0701cf7a include/xen/interface/io/kbdif.h
> --- a/include/xen/interface/io/kbdif.h Tue Jan 22 21:52:44 2008 +0000
> +++ b/include/xen/interface/io/kbdif.h Thu Jan 24 08:27:06 2008 -0700
> @@ -119,6 +119,10 @@ struct xenkbd_page
>      uint32_t out_cons, out_prod;
>  };
>  
> +#ifdef __KERNEL__
> +void xenkbd_set_ptr_geometry(int xres, int yres);
> +#endif
> +
>  #endif
>  
>  /*
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-devel



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.