[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC][PATCH v1] xen-fbfront: replace deferred io with buffer queue
hi Stefano, thank you for comments, On 1/19/2015 3:21 PM, Stefano Stabellini wrote: > On Mon, 19 Jan 2015, Sergiy Kibrik wrote: >> Use N-buffering instead of old deferred I/O, which is not suitable for high >> frame rates. This includes new event type -- xenfb_in_released, >> to track buffers not being used by backend. >> Also use grants for fb pages, as they allow backend to map them >> to video devices. > > Please make the grant change separately in another patch. > ok, will do it > >> Signed-off-by: Sergiy Kibrik <sergiy.kibrik@xxxxxxxxxxxxxxx> >> --- >> >> Hi, >> Here I'd like to present changes to xen-fbfront driver as example of >> how it can possibly be modified to support high frame rates. >> With this changes plus modified xenfb backend I was able to achieve 60 FPS on >> ARM based DRA7xx SoC, but this is rather display limitation, not driver >> itself. >> >> The idea is to send full resolution shared buffers to backend -- modern UI >> and >> multimedia applications cause heavy screen redraw. For this purpose driver >> allocates N-times bigger buffer than actual framebuffer resolution, each >> chunk >> assigned ID (0-N), which is carried within event message to backend. >> As soon as buffers displayed & released on host side, backend sends back >> release >> event with ID of released chunk, which can be used as framebuffer again. > > Isn't it going to use a lot of memory? Could you write down some example > configurations and relative memory consumption? yes, it is. E.g. on DRA7xx evaluation board with 800x480 display we adopted quad-buffering, this means we allocate around 6.8MB overall. However for traditional double-buffered case it's gonna be around 3.4Mb, affordable size for graphics use. > > >> For my setup I used modified Xen framebuffer backend [1], DRA7xx SoC and >> OMAP Display Subsystem for video output (omap_vout V4L2 driver). >> >> [1] http://www-archive.xenproject.org/files/summit_3/Xenpvfb.pdf >> >> drivers/video/fbdev/xen-fbfront.c | 344 >> ++++++++++++++++++++++++++----------- >> include/xen/interface/io/fbif.h | 9 +- >> 2 files changed, 250 insertions(+), 103 deletions(-) >> >> diff --git a/drivers/video/fbdev/xen-fbfront.c >> b/drivers/video/fbdev/xen-fbfront.c >> index 09dc447..a3e40ac 100644 >> --- a/drivers/video/fbdev/xen-fbfront.c >> +++ b/drivers/video/fbdev/xen-fbfront.c >> @@ -11,13 +11,7 @@ >> * more details. >> */ >> >> -/* >> - * TODO: >> - * >> - * Switch to grant tables when they become capable of dealing with the >> - * frame buffer. >> - */ >> - >> +/*#define DEBUG*/ > > spurious change? no, it was left intentionally as a hint for turning debug messages on. But if it's redundant I can remove one. > > >> #include <linux/console.h> >> #include <linux/kernel.h> >> #include <linux/errno.h> >> @@ -32,20 +26,34 @@ >> #include <xen/xen.h> >> #include <xen/events.h> >> #include <xen/page.h> >> +#include <xen/grant_table.h> >> #include <xen/interface/io/fbif.h> >> #include <xen/interface/io/protocols.h> >> #include <xen/xenbus.h> >> #include <xen/platform_pci.h> >> >> +enum xenfb_buf_state { >> + XENFB_BUF_RELEASED = 0, >> + XENFB_BUF_ACTIVE, >> + XENFB_BUF_NEXT, >> +}; > > Could you please add a comment to explain what are these states for? > Maybe you could also explain exactly how the new protocol works. > will do that > >> struct xenfb_info { >> unsigned char *fb; >> + int fb_size; >> struct fb_info *fb_info; >> int x1, y1, x2, y2; /* dirty rectangle, >> protected by dirty_lock */ >> - spinlock_t dirty_lock; >> + >> + spinlock_t b_lock; > > Why are you renaming the spinlock? If it is really necessary, please do > it in a separate patch. Mixing all the changes together makes the patch > difficult to read. lock renamed because it protects the whole xenfb_info object, not just rectangle attributes. I'll make up separate patch. > > >> + enum xenfb_buf_state *buffers; >> + int nr_buffers; >> int nr_pages; >> + struct completion completion; >> + >> int irq; >> struct xenfb_page *page; >> + int ring_ref; >> unsigned long *mfns; >> int update_wanted; /* XENFB_TYPE_UPDATE wanted */ >> int feature_resize; /* XENFB_TYPE_RESIZE ok */ >> @@ -70,6 +78,43 @@ 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 *rvmalloc(unsigned long size) >> +{ >> + void *mem; >> + unsigned long adr; >> + >> + size = PAGE_ALIGN(size); >> + mem = vmalloc_32(size); > > Is vmalloc_32 really needed? Could vmalloc be used? > no specific need for vmalloc_32, will correct that > >> + if (!mem) >> + return NULL; >> + >> + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ >> + adr = (unsigned long) mem; >> + while (size > 0) { >> + SetPageReserved(vmalloc_to_page((void *)adr)); >> + adr += PAGE_SIZE; >> + size -= PAGE_SIZE; >> + } >> + >> + return mem; >> +} >> + >> +static void rvfree(void *mem, unsigned long size) >> +{ >> + unsigned long adr; >> + >> + if (!mem) >> + return; >> + >> + adr = (unsigned long) mem; >> + while ((long) size > 0) { >> + ClearPageReserved(vmalloc_to_page((void *)adr)); >> + adr += PAGE_SIZE; >> + size -= PAGE_SIZE; >> + } >> + vfree(mem); >> +} >> + >> static void xenfb_send_event(struct xenfb_info *info, >> union xenfb_out_event *event) >> { >> @@ -147,7 +192,7 @@ static void xenfb_refresh(struct xenfb_info *info, >> if (!info->update_wanted) >> return; >> >> - spin_lock_irqsave(&info->dirty_lock, flags); >> + spin_lock_irqsave(&info->b_lock, flags); >> >> /* Combine with dirty rectangle: */ >> if (info->y1 < y1) >> @@ -165,7 +210,7 @@ static void xenfb_refresh(struct xenfb_info *info, >> info->x2 = x2; >> info->y1 = y1; >> info->y2 = y2; >> - spin_unlock_irqrestore(&info->dirty_lock, flags); >> + spin_unlock_irqrestore(&info->b_lock, flags); >> return; >> } >> >> @@ -173,42 +218,12 @@ static void xenfb_refresh(struct xenfb_info *info, >> info->x1 = info->y1 = INT_MAX; >> info->x2 = info->y2 = 0; >> >> - spin_unlock_irqrestore(&info->dirty_lock, flags); >> + spin_unlock_irqrestore(&info->b_lock, flags); >> >> if (x1 <= x2 && y1 <= y2) >> xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); >> } >> >> -static void xenfb_deferred_io(struct fb_info *fb_info, >> - struct list_head *pagelist) >> -{ >> - struct xenfb_info *info = fb_info->par; >> - struct page *page; >> - unsigned long beg, end; >> - int y1, y2, miny, maxy; >> - >> - miny = INT_MAX; >> - maxy = 0; >> - list_for_each_entry(page, pagelist, lru) { >> - beg = page->index << PAGE_SHIFT; >> - end = beg + PAGE_SIZE - 1; >> - y1 = beg / fb_info->fix.line_length; >> - y2 = end / fb_info->fix.line_length; >> - if (y2 >= fb_info->var.yres) >> - y2 = fb_info->var.yres - 1; >> - if (miny > y1) >> - miny = y1; >> - if (maxy < y2) >> - maxy = y2; >> - } >> - xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1); >> -} >> - >> -static struct fb_deferred_io xenfb_defio = { >> - .delay = HZ / 20, >> - .deferred_io = xenfb_deferred_io, >> -}; >> - >> static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, >> unsigned blue, unsigned transp, >> struct fb_info *info) >> @@ -275,26 +290,40 @@ static ssize_t xenfb_write(struct fb_info *p, const >> char __user *buf, >> return res; >> } >> >> +static int find_released(struct xenfb_info *info) >> +{ >> + int i; >> + for (i = 0; i < info->nr_buffers; i++) >> + if (info->buffers[i] == XENFB_BUF_RELEASED) >> + return i; >> + return -1; >> +} >> + >> static int >> xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) >> { >> struct xenfb_info *xenfb_info; >> int required_mem_len; >> + int buffer; >> + unsigned long flags; >> >> 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; >> - } >> + if (var->xres != video[KPARAM_WIDTH] || >> + var->yres != video[KPARAM_HEIGHT] || >> + var->bits_per_pixel != xenfb_info->page->depth) >> return -EINVAL; >> - } >> >> - /* Can't resize past initial width and height */ >> - if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT]) >> - return -EINVAL; >> + if (xenfb_queue_full(xenfb_info)) >> + return -EBUSY; >> + >> + spin_lock_irqsave(&xenfb_info->b_lock, flags); >> + buffer = var->yoffset / var->yres; >> + if (find_released(xenfb_info) == -1) { >> + spin_unlock_irqrestore(&xenfb_info->b_lock, flags); >> + return -EBUSY; >> + } >> + spin_unlock_irqrestore(&xenfb_info->b_lock, flags); >> >> required_mem_len = var->xres * var->yres * xenfb_info->page->depth / 8; >> if (var->bits_per_pixel == xenfb_info->page->depth && >> @@ -307,25 +336,85 @@ xenfb_check_var(struct fb_var_screeninfo *var, struct >> fb_info *info) >> return -EINVAL; >> } >> >> -static int xenfb_set_par(struct fb_info *info) >> +static int xenfb_set_par(struct fb_info *fbi) >> { >> - struct xenfb_info *xenfb_info; >> + struct xenfb_info *info = fbi->par; >> + struct xenbus_device *xbdev = info->xbdev; >> + struct fb_var_screeninfo *var = &fbi->var; >> + int buffer = var->yoffset / var->yres; >> unsigned long flags; >> >> - xenfb_info = info->par; >> + BUG_ON(buffer < 0 || buffer >= info->nr_buffers); >> + >> + xenfb_do_update(info, var->xoffset, var->yoffset, >> + var->xres, var->yres); >> + dev_dbg(&xbdev->dev, "sent buf %d\n", buffer); >> + >> + spin_lock_irqsave(&info->b_lock, flags); >> + info->buffers[buffer] = XENFB_BUF_NEXT; >> + buffer = find_released(info); >> + if (buffer != -1) { >> + var->yoffset = var->yres * buffer; >> + dev_dbg(&xbdev->dev, "giving out %d\n", buffer); >> + spin_unlock_irqrestore(&info->b_lock, flags); >> + return 0; >> + } >> >> - spin_lock_irqsave(&xenfb_info->resize_lock, flags); >> - xenfb_info->resize.type = XENFB_TYPE_RESIZE; >> - 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.offset = 0; >> - xenfb_info->resize_dpy = 1; >> - spin_unlock_irqrestore(&xenfb_info->resize_lock, flags); >> + /* If no buffers available, e.g. in case of double-buffering, >> + * we have to wait for backend to release some. If backend is >> + * already dead, we return last buffer and hope >> + * client knows what to do >> + */ >> + INIT_COMPLETION(info->completion); >> + spin_unlock_irqrestore(&info->b_lock, flags); >> + >> + if (wait_for_completion_interruptible_timeout(&info->completion, >> + msecs_to_jiffies(40)) <= 0) { >> + dev_dbg(&xbdev->dev, "no buffer after timeout\n"); >> + return -ETIMEDOUT; >> + } >> + >> + spin_lock_irqsave(&info->b_lock, flags); >> + buffer = find_released(info); >> + spin_unlock_irqrestore(&info->b_lock, flags); >> + BUG_ON(buffer == -1); /* wtf is going on? */ >> + var->yoffset = var->yres * buffer; >> + >> + dev_dbg(&xbdev->dev, "given %d after wait\n", buffer); >> return 0; >> } >> >> +static int xenfb_mmap(struct fb_info *fbi, >> + struct vm_area_struct *vma) >> +{ >> + struct xenfb_info *info = fbi->par; >> + unsigned long start = vma->vm_start; >> + unsigned long size = vma->vm_end - vma->vm_start; >> + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; >> + unsigned long page, pos; >> + >> + if (offset + size > fbi->fix.smem_len) >> + return -EINVAL; >> + >> + pos = (unsigned long)info->fb + offset; >> + >> + while (size > 0) { >> + page = vmalloc_to_pfn((void *)pos); >> + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) >> + return -EAGAIN; >> + >> + start += PAGE_SIZE; >> + pos += PAGE_SIZE; >> + if (size > PAGE_SIZE) >> + size -= PAGE_SIZE; >> + else >> + size = 0; >> + } >> + >> + return 0; >> + >> +} >> + >> static struct fb_ops xenfb_fb_ops = { >> .owner = THIS_MODULE, >> .fb_read = fb_sys_read, >> @@ -336,26 +425,36 @@ static struct fb_ops xenfb_fb_ops = { >> .fb_imageblit = xenfb_imageblit, >> .fb_check_var = xenfb_check_var, >> .fb_set_par = xenfb_set_par, >> + .fb_mmap = xenfb_mmap, >> }; >> >> static irqreturn_t xenfb_event_handler(int rq, void *dev_id) >> { >> - /* >> - * No in events recognized, simply ignore them all. >> - * If you need to recognize some, see xen-kbdfront's >> - * input_handler() for how to do that. >> - */ >> struct xenfb_info *info = dev_id; >> struct xenfb_page *page = info->page; >> + uint32_t cons, in_prod; >> + unsigned long flags; >> >> - if (page->in_cons != page->in_prod) { >> - info->page->in_cons = info->page->in_prod; >> - notify_remote_via_irq(info->irq); >> + rmb(); >> + in_prod = page->in_prod; >> + dev_dbg(&info->xbdev->dev, "handle %d in events\n", in_prod); >> + >> + spin_lock_irqsave(&info->b_lock, flags); >> + for (cons = page->in_cons; cons != in_prod; cons++) { >> + union xenfb_in_event *event = &XENFB_IN_RING_REF(page, cons); >> + if (event->type == XENFB_TYPE_RELEASE) { >> + int buffer = event->release.buffer; >> + if (buffer < 0 || buffer >= info->nr_buffers) >> + continue; >> + info->buffers[buffer] = XENFB_BUF_RELEASED; >> + dev_dbg(&info->xbdev->dev, "released %d\n", buffer); >> + complete(&info->completion); >> + } >> } >> + page->in_cons = cons; >> + spin_unlock_irqrestore(&info->b_lock, flags); >> >> - /* Flush dirty rectangle: */ >> - xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX); >> - >> + mb(); >> return IRQ_HANDLED; >> } >> >> @@ -364,8 +463,6 @@ static int xenfb_probe(struct xenbus_device *dev, >> { >> struct xenfb_info *info; >> struct fb_info *fb_info; >> - int fb_size; >> - int val; >> int ret = 0; >> >> info = kzalloc(sizeof(*info), GFP_KERNEL); >> @@ -375,42 +472,50 @@ static int xenfb_probe(struct xenbus_device *dev, >> } >> >> /* 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] * 1024 * 1024; >> - if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8 >> - > fb_size) { >> + if (xenbus_scanf(XBT_NIL, dev->otherend, >> + "num_bufs", "%d", &info->nr_buffers) != 1) >> + info->nr_buffers = 2; > > This doesn't sound like a secure interface: a potentially very > significant and unbound memory allocation in dom0 is caused by a > parameter configured by the guest. > > It can be trivial for a malicious guest to take down the system. > >> + if (xenbus_scanf(XBT_NIL, dev->otherend, "size", "%dx%d", >> + &video[KPARAM_WIDTH], &video[KPARAM_HEIGHT]) != 2) { >> video[KPARAM_WIDTH] = XENFB_WIDTH; >> video[KPARAM_HEIGHT] = XENFB_HEIGHT; >> - fb_size = XENFB_DEFAULT_FB_LEN; >> } >> >> dev_set_drvdata(&dev->dev, info); >> info->xbdev = dev; >> info->irq = -1; >> info->x1 = info->y1 = INT_MAX; >> - spin_lock_init(&info->dirty_lock); >> + spin_lock_init(&info->b_lock); >> spin_lock_init(&info->resize_lock); >> + init_completion(&info->completion); >> >> - info->fb = vzalloc(fb_size); >> + info->fb_size = video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * >> + (XENFB_DEPTH / 8) * info->nr_buffers; >> + info->fb = rvmalloc(info->fb_size); >> if (info->fb == NULL) >> goto error_nomem; >> >> - info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; >> + info->nr_pages = (info->fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; >> >> info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); >> if (!info->mfns) >> goto error_nomem; >> + info->buffers = kzalloc(sizeof(info->buffers[0]) * info->nr_buffers, >> + GFP_KERNEL); >> + if (!info->buffers) >> + goto error_nomem; >> >> /* set up shared page */ >> info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); >> if (!info->page) >> goto error_nomem; >> >> + memset(info->page->pd, -1, sizeof(info->page->pd)); >> + >> + info->ring_ref = xenbus_grant_ring(dev, virt_to_mfn(info->page)); >> + if (info->ring_ref < 0) >> + goto error; >> + >> /* abusing framebuffer_alloc() to allocate pseudo_palette */ >> fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); >> if (fb_info == NULL) >> @@ -438,11 +543,13 @@ static int xenfb_probe(struct xenbus_device *dev, >> >> fb_info->fix.visual = FB_VISUAL_TRUECOLOR; >> fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8; >> - fb_info->fix.smem_start = 0; >> - fb_info->fix.smem_len = fb_size; >> + fb_info->fix.smem_start = >> + (unsigned long)page_to_phys(vmalloc_to_page(info->fb)); >> + fb_info->fix.smem_len = info->fb_size; >> strcpy(fb_info->fix.id, "xen"); >> fb_info->fix.type = FB_TYPE_PACKED_PIXELS; >> fb_info->fix.accel = FB_ACCEL_NONE; >> + fb_info->fix.ypanstep = fb_info->var.yres; >> >> fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; >> >> @@ -453,9 +560,6 @@ static int xenfb_probe(struct xenbus_device *dev, >> goto error; >> } >> >> - fb_info->fbdefio = &xenfb_defio; >> - fb_deferred_io_init(fb_info); >> - >> xenfb_init_shared_page(info, fb_info); >> >> ret = xenfb_connect_backend(dev, info); >> @@ -521,6 +625,7 @@ static int xenfb_resume(struct xenbus_device *dev) >> static int xenfb_remove(struct xenbus_device *dev) >> { >> struct xenfb_info *info = dev_get_drvdata(&dev->dev); >> + int i; >> >> xenfb_disconnect_backend(info); >> if (info->fb_info) { >> @@ -529,9 +634,26 @@ static int xenfb_remove(struct xenbus_device *dev) >> fb_dealloc_cmap(&info->fb_info->cmap); >> framebuffer_release(info->fb_info); >> } >> + >> + for (i = 0; i < sizeof(info->page->pd); i++) >> + if (info->page->pd[i] != -1) { >> + gnttab_end_foreign_access( >> + info->page->pd[i], 0, 0UL); >> + info->page->pd[i] = -1; >> + } >> + >> + if (info->ring_ref >= 0) { >> + gnttab_end_foreign_access(info->ring_ref, 0, 0UL); >> + info->ring_ref = -1; >> + } >> + >> free_page((unsigned long)info->page); >> + >> + for (i = 0; i < info->nr_pages; i++) >> + gnttab_end_foreign_access(info->mfns[i], 0, 0UL); >> vfree(info->mfns); >> - vfree(info->fb); >> + rvfree(info->fb, info->fb_size); >> + kfree(info->buffers); >> kfree(info); >> >> return 0; >> @@ -545,14 +667,32 @@ static unsigned long vmalloc_to_mfn(void *address) >> static void xenfb_init_shared_page(struct xenfb_info *info, >> struct fb_info *fb_info) >> { >> - int i; >> + int i, ref; >> + grant_ref_t gref_head; >> int epd = PAGE_SIZE / sizeof(info->mfns[0]); >> >> - for (i = 0; i < info->nr_pages; i++) >> - info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); >> + if (gnttab_alloc_grant_references(info->nr_pages + >> + DIV_ROUND_UP(info->nr_pages, epd), >> + &gref_head)) { >> + WARN(1, "failed to allocate %u grants\n", info->nr_pages); >> + return; >> + } >> >> - for (i = 0; i * epd < info->nr_pages; i++) >> - info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); >> + for (i = 0; i < info->nr_pages; i++) { >> + ref = gnttab_claim_grant_reference(&gref_head); >> + BUG_ON(ref == -ENOSPC); >> + gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id, >> + vmalloc_to_mfn(info->fb + i * PAGE_SIZE), 0); >> + info->mfns[i] = ref; >> + } >> + >> + for (i = 0; i * epd < info->nr_pages; i++) { >> + ref = gnttab_claim_grant_reference(&gref_head); >> + BUG_ON(ref == -ENOSPC); >> + gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id, >> + vmalloc_to_mfn(&info->mfns[i * epd]), 0); >> + info->page->pd[i] = ref; >> + } >> >> info->page->width = fb_info->var.xres; >> info->page->height = fb_info->var.yres; >> @@ -585,8 +725,8 @@ static int xenfb_connect_backend(struct xenbus_device >> *dev, >> xenbus_dev_fatal(dev, ret, "starting transaction"); >> goto unbind_irq; >> } >> - ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", >> - virt_to_mfn(info->page)); >> + ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u", >> + info->ring_ref); >> if (ret) >> goto error_xenbus; >> ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", >> diff --git a/include/xen/interface/io/fbif.h >> b/include/xen/interface/io/fbif.h >> index 974a51e..471d867 100644 >> --- a/include/xen/interface/io/fbif.h >> +++ b/include/xen/interface/io/fbif.h >> @@ -77,13 +77,20 @@ union xenfb_out_event { >> >> /* >> * Frontends should ignore unknown in events. >> - * No in events currently defined. >> */ >> >> +#define XENFB_TYPE_RELEASE 4 >> +struct xenfb_release { >> + uint8_t type; /* XENFB_TYPE_RELEASE */ > > Isn't the type already stored in struct xenfb_in_event? > Why do you need it here too? Are there two different types? > > xenfb_in_event is a union. I just did it in the way union xenfb_out_event already implemented. -- regards, Sergey >> + int32_t buffer; /* buffer # */ >> +}; >> + >> + >> #define XENFB_IN_EVENT_SIZE 40 >> >> union xenfb_in_event { >> uint8_t type; >> + struct xenfb_release release; >> char pad[XENFB_IN_EVENT_SIZE]; >> }; >> >> -- >> 1.7.9.5 >> >> >> _______________________________________________ >> Xen-devel mailing list >> Xen-devel@xxxxxxxxxxxxx >> http://lists.xen.org/xen-devel >> _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |