From: Michel Dänzer <daen...@vmware.com>

Use the fb_mmap hook for userspace and re-create the kernel mapping whenever the
fbcon BO moves back into VRAM. KMS will pin it when necessary. This way we
aren't wasting precious VRAM when we're e.g. in X.

fbcon shouldn't (and IME doesn't) touch the BO contents while it isn't
displaying. If userspace tries to access /dev/fb* with read/write while the BO
isn't in VRAM, we re-create the kernel mapping with vmap().

This means fbdev userspace will only be able to map the framebuffer via
/dev/fb*, not via /dev/mem, but that's hardly a loss.

Signed-off-by: Michel Dänzer <daen...@vmware.com>
---
 drivers/gpu/drm/Kconfig                |    1 +
 drivers/gpu/drm/radeon/radeon.h        |    1 -
 drivers/gpu/drm/radeon/radeon_device.c |    4 +--
 drivers/gpu/drm/radeon/radeon_fb.c     |   58 +++++++++++++++++++++++--------
 drivers/gpu/drm/radeon/radeon_gem.c    |    2 -
 drivers/gpu/drm/radeon/radeon_mode.h   |    5 +++
 drivers/gpu/drm/radeon/radeon_ttm.c    |   24 ++++++++++++-
 7 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c961fe4..34c2400 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -47,6 +47,7 @@ config DRM_RADEON
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
+       select FB_SYS_FOPS
        select FB
        select FRAMEBUFFER_CONSOLE if !EMBEDDED
        help
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 3cd43ce..43f7962 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -601,7 +601,6 @@ struct radeon_device {
        struct radeon_object            *stollen_vga_memory;
        struct fb_info                  *fbdev_info;
        struct radeon_object            *fbdev_robj;
-       struct radeon_framebuffer       *fbdev_rfb;
        /* Register mmio */
        unsigned long                   rmmio_base;
        unsigned long                   rmmio_size;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c 
b/drivers/gpu/drm/radeon/radeon_device.c
index a03eebd..a2418d4 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -705,9 +705,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t 
state)
                        continue;
                }
                robj = rfb->obj->driver_private;
-               if (robj != rdev->fbdev_robj) {
-                       radeon_object_unpin(robj);
-               }
+               radeon_object_unpin(robj);
        }
        /* evict vram memory */
        radeon_object_evict_vram(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c 
b/drivers/gpu/drm/radeon/radeon_fb.c
index 260870a..35d08be 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -404,6 +404,45 @@ int radeonfb_blank(int blank, struct fb_info *info)
        return 0;
 }
 
+static int radeonfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct radeon_object *robj = rfbdev->rfb->obj->driver_private;
+
+       return radeon_object_fbdev_mmap(robj, vma);
+}
+
+static void radeonfb_remap(struct fb_info *info)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct radeon_object *robj = rfbdev->rfb->obj->driver_private;
+
+       if (info->screen_base) {
+               radeon_object_kunmap(robj);
+               info->screen_base = NULL;
+       }
+       radeon_object_kmap(robj, (void**)&info->screen_base);
+
+       info->fbops->fb_read = fb_sys_read;
+       info->fbops->fb_write = fb_sys_write;
+}
+
+ssize_t radeonfb_read(struct fb_info *info, char __user *buf, size_t count,
+                     loff_t *ppos)
+{
+       radeonfb_remap(info);
+
+       return fb_sys_read(info, buf, count, ppos);
+}
+
+ssize_t radeonfb_write(struct fb_info *info, const char __user *buf,
+                      size_t count, loff_t *ppos)
+{
+       radeonfb_remap(info);
+
+       return fb_sys_write(info, buf, count, ppos);
+}
+
 static struct fb_ops radeonfb_ops = {
        .owner = THIS_MODULE,
        .fb_check_var = radeonfb_check_var,
@@ -414,6 +453,7 @@ static struct fb_ops radeonfb_ops = {
        .fb_imageblit = cfb_imageblit,
        .fb_pan_display = radeonfb_pan_display,
        .fb_blank = radeonfb_blank,
+       .fb_mmap = radeonfb_mmap,
 };
 
 /**
@@ -509,9 +549,7 @@ int radeonfb_create(struct radeon_device *rdev,
        struct radeon_object *robj = NULL;
        struct device *device = &rdev->pdev->dev;
        int size, aligned_size, ret;
-       u64 fb_gpuaddr;
        void *fbptr = NULL;
-       unsigned long tmp;
 
        mode_cmd.width = surface_width;
        mode_cmd.height = surface_height;
@@ -524,9 +562,8 @@ int radeonfb_create(struct radeon_device *rdev,
        aligned_size = ALIGN(size, PAGE_SIZE);
 
        ret = radeon_gem_object_create(rdev, aligned_size, 0,
-                       RADEON_GEM_DOMAIN_VRAM,
-                       false, ttm_bo_type_kernel,
-                       false, &gobj);
+                                      RADEON_GEM_DOMAIN_VRAM,
+                                      false, false, false, &gobj);
        if (ret) {
                printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
                       surface_width, surface_height);
@@ -542,18 +579,11 @@ int radeonfb_create(struct radeon_device *rdev,
                ret = -ENOMEM;
                goto out_unref;
        }
-       ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
-       if (ret) {
-               printk(KERN_ERR "failed to pin framebuffer\n");
-               ret = -ENOMEM;
-               goto out_unref;
-       }
 
        list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
 
        rfb = to_radeon_framebuffer(fb);
        *rfb_p = rfb;
-       rdev->fbdev_rfb = rfb;
        rdev->fbdev_robj = robj;
 
        info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
@@ -580,8 +610,7 @@ int radeonfb_create(struct radeon_device *rdev,
        info->flags = FBINFO_DEFAULT;
        info->fbops = &radeonfb_ops;
        info->fix.line_length = fb->pitch;
-       tmp = fb_gpuaddr - rdev->mc.vram_location;
-       info->fix.smem_start = rdev->mc.aper_base + tmp;
+       info->fix.smem_start = 0;
        info->fix.smem_len = size;
        info->screen_base = fbptr;
        info->screen_size = size;
@@ -870,7 +899,6 @@ int radeonfb_remove(struct drm_device *dev, struct 
drm_framebuffer *fb)
                robj = rfb->obj->driver_private;
                unregister_framebuffer(info);
                radeon_object_kunmap(robj);
-               radeon_object_unpin(robj);
                framebuffer_release(info);
        }
 
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c 
b/drivers/gpu/drm/radeon/radeon_gem.c
index c3dd0fc..c36d603 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -163,8 +163,6 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void 
*data,
        args->vram_visible = rdev->mc.vram_size;
        if (rdev->stollen_vga_memory)
                args->vram_visible -= 
radeon_object_size(rdev->stollen_vga_memory);
-       if (rdev->fbdev_robj)
-               args->vram_visible -= radeon_object_size(rdev->fbdev_robj);
        list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
                if (drm_helper_crtc_in_use(crtc)) {
                        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h 
b/drivers/gpu/drm/radeon/radeon_mode.h
index 99a35b1..67a79df 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -362,6 +362,11 @@ struct drm_framebuffer *radeon_framebuffer_create(struct 
drm_device *dev,
                                                  struct drm_mode_fb_cmd 
*mode_cmd,
                                                  struct drm_gem_object *obj);
 
+ssize_t radeonfb_read(struct fb_info *info, char __user *buf, size_t count,
+                     loff_t *ppos);
+ssize_t radeonfb_write(struct fb_info *info, const char __user *buf,
+                      size_t count, loff_t *ppos);
+
 int radeonfb_probe(struct drm_device *dev);
 
 int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c 
b/drivers/gpu/drm/radeon/radeon_ttm.c
index 8a3015c..5d901d2 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -350,7 +350,8 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,
             new_mem->mem_type == TTM_PL_TT)) {
                /* bind is enought */
                radeon_move_null(bo, new_mem);
-               return 0;
+               r = 0;
+               goto remap;
        }
        if (!rdev->cp.ready) {
                /* use memcpy */
@@ -375,6 +376,27 @@ memcpy:
                r = ttm_bo_move_memcpy(bo, evict, no_wait, new_mem);
        }
 
+remap:
+       if (likely(!r) && unlikely(bo == (struct 
ttm_buffer_object*)rdev->fbdev_robj)) {
+               struct fb_ops *ops = rdev->fbdev_info->fbops;
+
+               if (ttm_mem_reg_is_pci(bo->bdev, new_mem)) {
+                       if (rdev->fbdev_info->screen_base) {
+                               radeon_object_kunmap(rdev->fbdev_robj);
+                               rdev->fbdev_info->screen_base = NULL;
+                       }
+                       r = radeon_object_kmap(rdev->fbdev_robj, 
(void**)&rdev->fbdev_info->screen_base);
+                       if (!r) {
+                               ops->fb_read = NULL;
+                               ops->fb_write = NULL;
+                       }
+               } else {
+                       if (!ops->fb_read)
+                               ops->fb_read = radeonfb_read;
+                       if (!ops->fb_write)
+                               ops->fb_write = radeonfb_write;
+               }
+       }
        return r;
 }
 
-- 
1.6.3.3


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to