marcin.slusarz at gmail.com
2010-Apr-10 19:55 UTC
[Nouveau] [PATCH 1/3] fbmem: fix aperture overlapping check
fb_do_apertures_overlap is returning wrong value when one aperture is completely whithin the other. Add generic ranges_overlap macro (probably kernel.h candidate) and use it here. Signed-off-by: Marcin Slusarz <marcin.slusarz at gmail.com> Cc: Dave Airlie <airlied at redhat.com> Cc: Peter Jones <pjones at redhat.com> Cc: Andrew Morton <akpm at linux-foundation.org> --- drivers/video/fbmem.c | 24 +++++++++++++++++------- 1 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index a15b44e..41f2e5e 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1468,15 +1468,25 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } +/** + * ranges_overlap - check whether two ranges overlap (their intersection is not empty) + * @start1: start of the first range + * @size1: length of the first range + * @start2: start of the second range + * @size2: length of the second range + */ +#define ranges_overlap(start1, size1, start2, size2) ({ \ + typeof(start1) __start1 = (start1); \ + typeof(size1) __size1 = (size1); \ + typeof(start2) __start2 = (start2); \ + typeof(size2) __size2 = (size2); \ + __start1 < __start2 + __size2 && __start1 + __size1 > __start2; \ +}) + static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) { - /* is the generic aperture base the same as the HW one */ - if (gen->aperture_base == hw->aperture_base) - return true; - /* is the generic aperture base inside the hw base->hw base+size */ - if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) - return true; - return false; + return ranges_overlap(gen->aperture_base, gen->aperture_size, + hw->aperture_base, hw->aperture_size); } /** * register_framebuffer - registers a frame buffer device -- 1.7.0.4
marcin.slusarz at gmail.com
2010-Apr-10 19:55 UTC
[Nouveau] [PATCH 2/3] fbdev: allow passing more than one aperture for handoff
It simplifies nouveau code by removal of detection which region to pass to kick vesafb/efifb. Signed-off-by: Marcin Slusarz <marcin.slusarz at gmail.com> Cc: Eric Anholt <eric at anholt.net> Cc: Ben Skeggs <bskeggs at redhat.com> Cc: Thomas Hellstrom <thellstrom at vmware.com> Cc: Dave Airlie <airlied at redhat.com> Cc: Peter Jones <pjones at redhat.com> Cc: Andrew Morton <akpm at linux-foundation.org> Cc: Benjamin Herrenschmidt <benh at kernel.crashing.org> --- drivers/gpu/drm/i915/intel_fb.c | 11 +++- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 84 +++++++++--------------------- drivers/gpu/drm/radeon/radeon_fb.c | 9 +++- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 10 +++- drivers/video/efifb.c | 11 +++- drivers/video/fbmem.c | 20 +++++++- drivers/video/fbsysfs.c | 1 + drivers/video/offb.c | 28 ++++++---- drivers/video/vesafb.c | 11 +++- include/linux/fb.h | 16 +++++- 10 files changed, 114 insertions(+), 87 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 8cd791d..a9192ab 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -192,11 +192,16 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, /* setup aperture base/size for vesafb takeover */ - info->aperture_base = dev->mode_config.fb_base; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unpin; + } + info->apertures->ranges[0].base = dev->mode_config.fb_base; if (IS_I9XX(dev)) - info->aperture_size = pci_resource_len(dev->pdev, 2); + info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2); else - info->aperture_size = pci_resource_len(dev->pdev, 0); + info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; info->fix.smem_len = size; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 68cedd9..206368b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -161,44 +161,6 @@ static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { .gamma_get = nouveau_fbcon_gamma_get }; -#if defined(__i386__) || defined(__x86_64__) -static bool -nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) -{ - struct pci_dev *pdev = dev->pdev; - int ramin; - - if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB && - screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) - return false; - - if (screen_info.lfb_base < pci_resource_start(pdev, 1)) - goto not_fb; - - if (screen_info.lfb_base + screen_info.lfb_size >- pci_resource_start(pdev, 1) + pci_resource_len(pdev, 1)) - goto not_fb; - - return true; -not_fb: - ramin = 2; - if (pci_resource_len(pdev, ramin) == 0) { - ramin = 3; - if (pci_resource_len(pdev, ramin) == 0) - return false; - } - - if (screen_info.lfb_base < pci_resource_start(pdev, ramin)) - return false; - - if (screen_info.lfb_base + screen_info.lfb_size >- pci_resource_start(pdev, ramin) + pci_resource_len(pdev, ramin)) - return false; - - return true; -} -#endif - void nouveau_fbcon_zfill(struct drm_device *dev) { @@ -231,7 +193,9 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, struct nouveau_framebuffer *nouveau_fb; struct nouveau_bo *nvbo; struct drm_mode_fb_cmd mode_cmd; - struct device *device = &dev->pdev->dev; + struct pci_dev *pdev = dev->pdev; + struct device *device = &pdev->dev; + struct apertures_struct *aper; int size, ret; mode_cmd.width = surface_width; @@ -314,28 +278,30 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, drm_fb_helper_fill_var(info, fb, fb_width, fb_height); /* FIXME: we really shouldn't expose mmio space at all */ - info->fix.mmio_start = pci_resource_start(dev->pdev, 1); - info->fix.mmio_len = pci_resource_len(dev->pdev, 1); + info->fix.mmio_start = pci_resource_start(pdev, 1); + info->fix.mmio_len = pci_resource_len(pdev, 1); /* Set aperture base/size for vesafb takeover */ -#if defined(__i386__) || defined(__x86_64__) - if (nouveau_fbcon_has_vesafb_or_efifb(dev)) { - /* Some NVIDIA VBIOS' are stupid and decide to put the - * framebuffer in the middle of the PRAMIN BAR for - * whatever reason. We need to know the exact lfb_base - * to get vesafb kicked off, and the only reliable way - * we have left is to find out lfb_base the same way - * vesafb did. - */ - info->aperture_base = screen_info.lfb_base; - info->aperture_size = screen_info.lfb_size; - if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) - info->aperture_size *= 65536; - } else -#endif - { - info->aperture_base = info->fix.mmio_start; - info->aperture_size = info->fix.mmio_len; + aper = info->apertures = alloc_apertures(3); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unref; + } + + aper->ranges[0].base = pci_resource_start(pdev, 1); + aper->ranges[0].size = pci_resource_len(pdev, 1); + aper->count = 1; + + if (pci_resource_len(pdev, 2)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 2); + aper->ranges[aper->count].size = pci_resource_len(pdev, 2); + aper->count++; + } + + if (pci_resource_len(pdev, 3)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 3); + aper->ranges[aper->count].size = pci_resource_len(pdev, 3); + aper->count++; } info->pixmap.size = 64*1024; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 8fccbf2..2b57cb4 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -263,8 +263,13 @@ int radeonfb_create(struct drm_device *dev, drm_fb_helper_fill_var(info, fb, fb_width, fb_height); /* setup aperture base/size for vesafb takeover */ - info->aperture_base = rdev->ddev->mode_config.fb_base; - info->aperture_size = rdev->mc.real_vram_size; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto out_unref; + } + info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; + info->apertures->ranges[0].size = rdev->mc.real_vram_size; info->fix.mmio_start = 0; info->fix.mmio_len = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index a933670..0248c6b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -559,8 +559,13 @@ int vmw_fb_init(struct vmw_private *vmw_priv) info->pixmap.scan_align = 1; #endif - info->aperture_base = vmw_priv->vram_start; - info->aperture_size = vmw_priv->vram_size; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto err_aper; + } + info->apertures->ranges[0].base = vmw_priv->vram_start; + info->apertures->ranges[0].size = vmw_priv->vram_size; /* * Dirty & Deferred IO @@ -580,6 +585,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv) err_defio: fb_deferred_io_cleanup(info); +err_aper: ttm_bo_kunmap(&par->map); err_unref: ttm_bo_unref((struct ttm_buffer_object **)&par->vmw_bo); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 581d2db..3b98656 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -165,7 +165,7 @@ static void efifb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -289,8 +289,13 @@ static int __devinit efifb_probe(struct platform_device *dev) info->pseudo_palette = info->par; info->par = NULL; - info->aperture_base = efifb_fix.smem_start; - info->aperture_size = size_remap; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err_release_fb; + } + info->apertures->ranges[0].base = efifb_fix.smem_start; + info->apertures->ranges[0].size = size_remap; info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); if (!info->screen_base) { diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 41f2e5e..8824d2c 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1485,8 +1485,24 @@ static int fb_check_foreignness(struct fb_info *fi) static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) { - return ranges_overlap(gen->aperture_base, gen->aperture_size, - hw->aperture_base, hw->aperture_size); + int i, j; + struct apertures_struct *hwa = hw->apertures; + struct apertures_struct *gena = gen->apertures; + if (!hwa || !gena) + return false; + + for (i = 0; i < hwa->count; ++i) { + struct aperture *h = &hwa->ranges[i]; + for (j = 0; j < gena->count; ++j) { + struct aperture *g = &gena->ranges[j]; + printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", + g->base, g->size, h->base, h->size); + if (ranges_overlap(h->base, h->size, g->base, g->size)) + return true; + } + } + + return false; } /** * register_framebuffer - registers a frame buffer device diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index d4a2c11..fd5519b 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -79,6 +79,7 @@ EXPORT_SYMBOL(framebuffer_alloc); */ void framebuffer_release(struct fb_info *info) { + kfree(info->apertures); kfree(info); } EXPORT_SYMBOL(framebuffer_release); diff --git a/drivers/video/offb.c b/drivers/video/offb.c index b043ac8..3d202b2 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -286,7 +286,7 @@ static void offb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -492,8 +492,11 @@ static void __init offb_init_fb(const char *name, const char *full_name, var->vmode = FB_VMODE_NONINTERLACED; /* set offb aperture size for generic probing */ - info->aperture_base = address; - info->aperture_size = fix->smem_len; + info->apertures = alloc_apertures(1); + if (!info->apertures) + goto out_aper; + info->apertures->ranges[0].base = address; + info->apertures->ranges[0].size = fix->smem_len; info->fbops = &offb_ops; info->screen_base = ioremap(address, fix->smem_len); @@ -502,17 +505,20 @@ static void __init offb_init_fb(const char *name, const char *full_name, fb_alloc_cmap(&info->cmap, 256, 0); - if (register_framebuffer(info) < 0) { - iounmap(par->cmap_adr); - par->cmap_adr = NULL; - iounmap(info->screen_base); - framebuffer_release(info); - release_mem_region(res_start, res_size); - return; - } + if (register_framebuffer(info) < 0) + goto out_err; printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n", info->node, full_name); + return; + +out_err: + iounmap(info->screen_base); +out_aper: + iounmap(par->cmap_adr); + par->cmap_adr = NULL; + framebuffer_release(info); + release_mem_region(res_start, res_size); } diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index ef4128c..5de9ee1 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -178,7 +178,7 @@ static void vesafb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); - release_mem_region(info->aperture_base, info->aperture_size); + release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); framebuffer_release(info); } @@ -296,8 +296,13 @@ static int __devinit vesafb_probe(struct platform_device *dev) info->par = NULL; /* set vesafb aperture size for generic probing */ - info->aperture_base = screen_info.lfb_base; - info->aperture_size = size_total; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + err = -ENOMEM; + goto err; + } + info->apertures->ranges[0].base = screen_info.lfb_base; + info->apertures->ranges[0].size = size_total; info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); if (!info->screen_base) { diff --git a/include/linux/fb.h b/include/linux/fb.h index c10163b..9605b81 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -862,10 +862,22 @@ struct fb_info { /* we need the PCI or similiar aperture base/size not smem_start/size as smem_start may just be an object allocated inside the aperture so may not actually overlap */ - resource_size_t aperture_base; - resource_size_t aperture_size; + struct apertures_struct { + unsigned int count; + struct aperture { + resource_size_t base; + resource_size_t size; + } ranges[0]; + } *apertures; }; +static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { + struct apertures_struct *a = kzalloc(sizeof(struct apertures_struct) + + max_num * sizeof(struct aperture), GFP_KERNEL); + a->count = max_num; + return a; +} + #ifdef MODULE #define FBINFO_DEFAULT FBINFO_MODULE #else -- 1.7.0.4
marcin.slusarz at gmail.com
2010-Apr-10 19:55 UTC
[Nouveau] [PATCH 3/3] fbmem, drm/nouveau: kick firmware framebuffers as soon as possible
Currently vesafb/efifb/... is kicked when hardware driver is registering framebuffer. To do it hardware must be fully functional, so there's a short window between start of initialisation and framebuffer registration when two drivers touch the hardware. Unfortunately sometimes it breaks nouveau initialisation. Fix it by kicking firmware driver(s) before we start touching the hardware. Reported-by: Didier Spaier <didier.spaier at epsm.fr> Signed-off-by: Marcin Slusarz <marcin.slusarz at gmail.com> Cc: Ben Skeggs <bskeggs at redhat.com> Cc: Dave Airlie <airlied at redhat.com> Cc: Peter Jones <pjones at redhat.com> Cc: Andrew Morton <akpm at linux-foundation.org> --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 + drivers/gpu/drm/nouveau/nouveau_fbcon.c | 19 +------------- drivers/gpu/drm/nouveau/nouveau_state.c | 43 +++++++++++++++++++++++++++++++ drivers/video/fbmem.c | 43 ++++++++++++++++++------------- include/linux/fb.h | 1 + 5 files changed, 72 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index cb16a1b..a1f61f7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -621,6 +621,8 @@ struct drm_nouveau_private { struct { struct dentry *channel_root; } debugfs; + + struct apertures_struct *apertures; }; static inline struct drm_nouveau_private * diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 206368b..5e4367b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -195,7 +195,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, struct drm_mode_fb_cmd mode_cmd; struct pci_dev *pdev = dev->pdev; struct device *device = &pdev->dev; - struct apertures_struct *aper; int size, ret; mode_cmd.width = surface_width; @@ -282,28 +281,12 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, info->fix.mmio_len = pci_resource_len(pdev, 1); /* Set aperture base/size for vesafb takeover */ - aper = info->apertures = alloc_apertures(3); + info->apertures = dev_priv->apertures; if (!info->apertures) { ret = -ENOMEM; goto out_unref; } - aper->ranges[0].base = pci_resource_start(pdev, 1); - aper->ranges[0].size = pci_resource_len(pdev, 1); - aper->count = 1; - - if (pci_resource_len(pdev, 2)) { - aper->ranges[aper->count].base = pci_resource_start(pdev, 2); - aper->ranges[aper->count].size = pci_resource_len(pdev, 2); - aper->count++; - } - - if (pci_resource_len(pdev, 3)) { - aper->ranges[aper->count].base = pci_resource_start(pdev, 3); - aper->ranges[aper->count].size = pci_resource_len(pdev, 3); - aper->count++; - } - info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; info->pixmap.access_align = 32; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index a9e9cf3..cfa3239 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -636,6 +636,43 @@ static void nouveau_OF_copy_vbios_to_ramin(struct drm_device *dev) #endif } +static struct apertures_struct *nouveau_get_apertures(struct drm_device *dev) +{ + struct pci_dev *pdev = dev->pdev; + struct apertures_struct *aper = alloc_apertures(3); + if (!aper) + return NULL; + + aper->ranges[0].base = pci_resource_start(pdev, 1); + aper->ranges[0].size = pci_resource_len(pdev, 1); + aper->count = 1; + + if (pci_resource_len(pdev, 2)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 2); + aper->ranges[aper->count].size = pci_resource_len(pdev, 2); + aper->count++; + } + + if (pci_resource_len(pdev, 3)) { + aper->ranges[aper->count].base = pci_resource_start(pdev, 3); + aper->ranges[aper->count].size = pci_resource_len(pdev, 3); + aper->count++; + } + + return aper; +} + +static int nouveau_remove_conflicting_drivers(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + dev_priv->apertures = nouveau_get_apertures(dev); + if (!dev_priv->apertures) + return -ENOMEM; + + remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb"); + return 0; +} + int nouveau_load(struct drm_device *dev, unsigned long flags) { struct drm_nouveau_private *dev_priv; @@ -723,6 +760,12 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", dev_priv->card_type, reg0); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + int ret = nouveau_remove_conflicting_drivers(dev); + if (ret) + return ret; + } + /* map larger RAMIN aperture on NV40 cards */ dev_priv->ramin = NULL; if (dev_priv->card_type >= NV_40) { diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 8824d2c..f5297a0 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1483,11 +1483,10 @@ static int fb_check_foreignness(struct fb_info *fi) __start1 < __start2 + __size2 && __start1 + __size1 > __start2; \ }) -static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) +static bool fb_do_apertures_overlap(struct apertures_struct *gena, + struct apertures_struct *hwa) { int i, j; - struct apertures_struct *hwa = hw->apertures; - struct apertures_struct *gena = gen->apertures; if (!hwa || !gena) return false; @@ -1504,6 +1503,28 @@ static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) return false; } + +void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name) +{ + int i; + + /* check all firmware fbs and kick off if the base addr overlaps */ + for (i = 0 ; i < FB_MAX; i++) { + if (!registered_fb[i]) + continue; + + if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) + continue; + + if (fb_do_apertures_overlap(registered_fb[i]->apertures, a)) { + printk(KERN_ERR "fb: conflicting fb hw usage " + "%s vs %s - removing generic driver\n", + name, registered_fb[i]->fix.id); + unregister_framebuffer(registered_fb[i]); + } + } +} + /** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure @@ -1527,21 +1548,7 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; - /* check all firmware fbs and kick off if the base addr overlaps */ - for (i = 0 ; i < FB_MAX; i++) { - if (!registered_fb[i]) - continue; - - if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) { - if (fb_do_apertures_overlap(registered_fb[i], fb_info)) { - printk(KERN_ERR "fb: conflicting fb hw usage " - "%s vs %s - removing generic driver\n", - fb_info->fix.id, - registered_fb[i]->fix.id); - unregister_framebuffer(registered_fb[i]); - } - } - } + remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) diff --git a/include/linux/fb.h b/include/linux/fb.h index 9605b81..9e854a7 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -970,6 +970,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, /* drivers/video/fbmem.c */ extern int register_framebuffer(struct fb_info *fb_info); extern int unregister_framebuffer(struct fb_info *fb_info); +extern void remove_conflicting_framebuffers(struct apertures_struct *a, const char *name); extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); extern int fb_show_logo(struct fb_info *fb_info, int rotate); extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); -- 1.7.0.4
Dave Airlie
2010-Apr-11 23:54 UTC
[Nouveau] [PATCH 1/3] fbmem: fix aperture overlapping check
On Sat, 2010-04-10 at 21:55 +0200, marcin.slusarz at gmail.com wrote:> fb_do_apertures_overlap is returning wrong value when one aperture > is completely whithin the other. Add generic ranges_overlap macro > (probably kernel.h candidate) and use it here. >That doesn't seem right. The rules are: the generic aperture has to be equal or smaller than the hw aperture, otherwise the generic driver will be trashing random hw pieces on the machine. So with that in mind, the check makes sure the generic aperture starts somewhere inside the hw aperture, which the test clearly gets right. Have you got a pointer to a machine where it fails? Dave.> Signed-off-by: Marcin Slusarz <marcin.slusarz at gmail.com> > Cc: Dave Airlie <airlied at redhat.com> > Cc: Peter Jones <pjones at redhat.com> > Cc: Andrew Morton <akpm at linux-foundation.org> > --- > drivers/video/fbmem.c | 24 +++++++++++++++++------- > 1 files changed, 17 insertions(+), 7 deletions(-) > > diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c > index a15b44e..41f2e5e 100644 > --- a/drivers/video/fbmem.c > +++ b/drivers/video/fbmem.c > @@ -1468,15 +1468,25 @@ static int fb_check_foreignness(struct fb_info *fi) > return 0; > } > > +/** > + * ranges_overlap - check whether two ranges overlap (their intersection is not empty) > + * @start1: start of the first range > + * @size1: length of the first range > + * @start2: start of the second range > + * @size2: length of the second range > + */ > +#define ranges_overlap(start1, size1, start2, size2) ({ \ > + typeof(start1) __start1 = (start1); \ > + typeof(size1) __size1 = (size1); \ > + typeof(start2) __start2 = (start2); \ > + typeof(size2) __size2 = (size2); \ > + __start1 < __start2 + __size2 && __start1 + __size1 > __start2; \ > +}) > + > static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw) > { > - /* is the generic aperture base the same as the HW one */ > - if (gen->aperture_base == hw->aperture_base) > - return true; > - /* is the generic aperture base inside the hw base->hw base+size */ > - if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size) > - return true; > - return false; > + return ranges_overlap(gen->aperture_base, gen->aperture_size, > + hw->aperture_base, hw->aperture_size); > } > /** > * register_framebuffer - registers a frame buffer device
Reasonably Related Threads
- [PATCHv2 1/2] fbdev: allow passing more than one aperture for handoff
- Building Nouveau DRM for a recent kernel (linux-2.6.35-rc1)
- [PATCH v3 1/3] fbdev: allow passing more than one aperture for handoff
- [PATCH] vga16fb: refuse to load in face of other driver controlling primary card
- [PATCH v3 00/13] remove_conflicting_framebuffers() cleanup