From fa4c0aec111e356531468e4c8b568cf78bef6ab7 Mon Sep 17 00:00:00 2001 From: Stefan Bader Date: Thu, 6 Sep 2012 15:14:56 +0200 Subject: [PATCH] UBUNTU: SAUCE: Wait for resources when switching framebuffers When one framebuffer is to replace another, wait until the old one really is freed (and has released its ressources). Currently also carries some debugging output. Signed-off-by: Stefan Bader --- drivers/gpu/drm/cirrus/cirrus_main.c | 1 + drivers/video/efifb.c | 10 ++++++++-- drivers/video/fbmem.c | 13 +++++++++++++ include/linux/fb.h | 3 +++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index e3c1225..2585588 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -108,6 +108,7 @@ static int cirrus_vram_init(struct cirrus_device *cdev) /* We have 4MB of VRAM */ cdev->mc.vram_size = 4 * 1024 * 1024; + printk(KERN_INFO "cirrus: requesting framebuffer region\n"); if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size, "cirrusdrmfb_vram")) { DRM_ERROR("can't reserve VRAM\n"); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 0def0df..35b1276 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -288,9 +288,12 @@ static void efifb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - if (request_mem_succeeded) + if (request_mem_succeeded) { release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); + printk(KERN_INFO "efifb: frambuffer region released\n"); + } + framebuffer_release(info); } @@ -432,6 +435,7 @@ static int __init efifb_probe(struct platform_device *dev) efifb_fix.smem_len = size_remap; if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) { + printk(KERN_INFO "efifb: framebuffer region reserved\n"); request_mem_succeeded = true; } else { /* We cannot make this fatal. Sometimes this comes from magic @@ -536,8 +540,10 @@ err_unmap: err_release_fb: framebuffer_release(info); err_release_mem: - if (request_mem_succeeded) + if (request_mem_succeeded) { release_mem_region(efifb_fix.smem_start, size_total); + printk(KERN_INFO "efifb: frambuffer region released\n"); + } return err; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 0dff12a..ad1bc84 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -64,10 +64,17 @@ static struct fb_info *get_fb_info(unsigned int idx) static void put_fb_info(struct fb_info *fb_info) { + struct completion *cp = fb_info->notify_release; + if (!atomic_dec_and_test(&fb_info->count)) return; if (fb_info->fbops->fb_destroy) fb_info->fbops->fb_destroy(fb_info); + + if (cp) { + printk(KERN_WARNING "fb: final put_fb_info()\n"); + complete(cp); + } } int lock_fb_info(struct fb_info *info) @@ -1658,6 +1665,7 @@ static int do_register_framebuffer(struct fb_info *fb_info) static int do_unregister_framebuffer(struct fb_info *fb_info) { + struct completion resource_wait; struct fb_event event; int i, ret = 0; @@ -1686,7 +1694,12 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); /* this may free fb info */ + init_completion(&resource_wait); + fb_info->notify_release = &resource_wait; put_fb_info(fb_info); + /* wait until the framebuffer is really done */ + wait_for_completion(&resource_wait); + return 0; } diff --git a/include/linux/fb.h b/include/linux/fb.h index ac3f1c6..78036d0 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -5,6 +5,7 @@ #include #ifdef __KERNEL__ #include +#include #endif /* __KERNEL__ */ /* Definitions of frame buffers */ @@ -898,6 +899,8 @@ struct fb_info { resource_size_t size; } ranges[0]; } *apertures; + /* Optional notification hook for releasing resources */ + struct completion *notify_release; }; static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { -- 1.7.9.5