[RFC] drm/gma500: add virtual mapping support for fbdev.

jiang.biao2 at zte.com.cn jiang.biao2 at zte.com.cn
Tue Sep 6 11:28:02 UTC 2016


Hi,

I found current gma500 fbdev driver does not support the virtual 
mapping for the fb pages, instead it only uses stolen pages and 
supports high resolution console by reducing the color depth. It 
works well with fbcon for high resolution envirnment.

However, other programs, such as plymouth(a boot animation program) 
may also use fbdev driver to flush screen in high resolution 
envirnment, in that case, reducing the color depth will decrease the 
quality or result in other problem. 

Noticed that Alan's patch(commit 
dffc9ceb55695f121adc57dd1fde7304c3afe81e) killed the virtual mapping 
support for short of vmap space. But the vmalloc space(128M) should 
be enough for most high resolution envirnments.

So I'm considering add the virual mapping support for fbdev driver. 
The following patch has not done completely yet, still having console 
flicking problem need to be solved.

I'm not sure whether the patch will be useful for others or if there
is something I missed. Need your comments.

Thanks.

Signed-off-by: Jiang Biao<jiang.biao2 at zte.com.cn>

---
 drivers/gpu/drm/gma500/framebuffer.c | 110 
++++++++++++++++++++++-------------
 drivers/gpu/drm/gma500/framebuffer.h |   2 +
 2 files changed, 73 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/gma500/framebuffer.c 
b/drivers/gpu/drm/gma500/framebuffer.c
index 0fcdce0..21f14df 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -117,34 +117,43 @@ static int psbfb_vm_fault(struct vm_area_struct 
*vma, struct vm_fault *vmf)
        struct psb_framebuffer *psbfb = vma->vm_private_data;
        struct drm_device *dev = psbfb->base.dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
-       int page_num;
-       int i;
-       unsigned long address;
        int ret;
        unsigned long pfn;
-       unsigned long phys_addr = (unsigned long)dev_priv->stolen_base +
-                                 psbfb->gtt->offset;
-
-       page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-       address = (unsigned long)vmf->virtual_address - (vmf->pgoff << 
PAGE_SHIFT);
-
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-       for (i = 0; i < page_num; i++) {
-               pfn = (phys_addr >> PAGE_SHIFT);
-
-               ret = vm_insert_mixed(vma, address,
-                               __pfn_to_pfn_t(pfn, PFN_DEV));
-               if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0)))
-                       break;
-               else if (unlikely(ret != 0)) {
-                       ret = (ret == -ENOMEM) ? VM_FAULT_OOM : 
VM_FAULT_SIGBUS;
-                       return ret;
+       struct gtt_range *r;
+       pgoff_t page_offset;
+       r = psbfb->gtt;
+
+       mutex_lock(&dev->struct_mutex);
+       if (r->mmapping == 0) {
+               ret = psb_gtt_pin(r);
+               if (ret < 0) {
+                        goto fail;
                }
-               address += PAGE_SIZE;
-               phys_addr += PAGE_SIZE;
+               r->mmapping = 1;
+       }
+
+       page_offset = ((unsigned long) vmf->virtual_address - 
vma->vm_start)
+                               >> PAGE_SHIFT;
+
+       if (r->stolen)
+               pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT;
+       else
+               pfn = page_to_pfn(r->pages[page_offset]);
+
+       ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, 
pfn);
+
+fail:
+       mutex_unlock(&dev->struct_mutex);
+       switch (ret) {
+       case 0:
+       case -ERESTARTSYS:
+       case -EINTR:
+               return VM_FAULT_NOPAGE;
+       case -ENOMEM:
+               return VM_FAULT_OOM;
+       default:
+               return VM_FAULT_SIGBUS;
        }
-       return VM_FAULT_NOPAGE;
 }
 
 static void psbfb_vm_open(struct vm_area_struct *vma)
@@ -180,7 +189,7 @@ static int psbfb_mmap(struct fb_info *info, struct 
vm_area_struct *vma)
         */
        vma->vm_ops = &psbfb_vm_ops;
        vma->vm_private_data = (void *)psbfb;
-       vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | 
VM_DONTDUMP;
+       vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
        return 0;
 }
 
@@ -317,7 +326,17 @@ static struct gtt_range *psbfb_alloc(struct 
drm_device *dev, int aligned_size)
                drm_gem_private_object_init(dev, &backing->gem, 
aligned_size);
                return backing;
        }
-       return NULL;
+       /* Next try using GEM host memory */
+        backing = psb_gtt_alloc_range(dev, aligned_size, "fb(gem)", 0, 
PAGE_SIZE);
+        if (backing == NULL)
+                return NULL;
+
+        /* Now back it with an object */
+        if (drm_gem_object_init(dev, &backing->gem, aligned_size) != 0) {
+                psb_gtt_free_range(dev, backing);
+                return NULL;
+        }
+        return backing;
 }
 
 /**
@@ -397,7 +416,8 @@ static int psbfb_create(struct psb_fbdev *fbdev,
                        return -ENOMEM;
        }
 
-       memset(dev_priv->vram_addr + backing->offset, 0, size);
+       if (backing->stolen)
+               memset(dev_priv->vram_addr + backing->offset, 0, size);
 
        info = drm_fb_helper_alloc_fbi(&fbdev->psb_fb_helper);
        if (IS_ERR(info)) {
@@ -434,8 +454,20 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        info->fix.ywrapstep = gtt_roll;
        info->fix.ypanstep = 0;
 
-       /* Accessed stolen memory directly */
-       info->screen_base = dev_priv->vram_addr + backing->offset;
+       if (backing->stolen) {
+               info->screen_base = dev_priv->vram_addr + backing->offset;
+       } else {
+               psb_gtt_pin(backing);
+               backing->mapping = 1;
+               info->screen_base = vm_map_ram(backing->pages, 
backing->npage, -1, PAGE_KERNEL);
+               if (info->screen_base == NULL) {
+                       ret = -ENOMEM;
+                       goto err_free_range;
+               }
+               psbfb->vm_map = 1;
+ 
+       }
+
        info->screen_size = size;
 
        if (dev_priv->gtt.stolen_size) {
@@ -458,7 +490,10 @@ static int psbfb_create(struct psb_fbdev *fbdev,
 err_release:
        drm_fb_helper_release_fbi(&fbdev->psb_fb_helper);
 err_free_range:
-       psb_gtt_free_range(dev, backing);
+       if (backing->stolen)
+               psb_gtt_free_range(dev, backing);
+       else if(psbfb->vm_map)
+               vm_unmap_ram(info->screen_base, backing->npage);
        return ret;
 }
 
@@ -523,15 +558,6 @@ static int psbfb_probe(struct drm_fb_helper *helper,
        if (bytespp == 3)       /* no 24bit packed */
                bytespp = 4;
 
-       /* If the mode will not fit in 32bit then switch to 16bit to get
-          a console on full resolution. The X mode setting server will
-          allocate its own 32bit GEM framebuffer */
-       if (ALIGN(sizes->fb_width * bytespp, 64) * sizes->fb_height >
-                       dev_priv->vram_stolen_size) {
-                sizes->surface_bpp = 16;
-                sizes->surface_depth = 16;
-        }
-
        return psbfb_create(psb_fbdev, sizes);
 }
 
@@ -545,6 +571,12 @@ static int psb_fbdev_destroy(struct drm_device *dev, 
struct psb_fbdev *fbdev)
 {
        struct psb_framebuffer *psbfb = &fbdev->pfb;
 
+       info = fbdev->psb_fb_helper.fbdev;
+       if (psbfb->vm_map) {
+               vm_unmap_ram(info->screen_base, psbfb->gtt->npage);
+               psb_gtt_unpin(psbfb->gtt);
+       }
+
        drm_fb_helper_unregister_fbi(&fbdev->psb_fb_helper);
        drm_fb_helper_release_fbi(&fbdev->psb_fb_helper);
 
diff --git a/drivers/gpu/drm/gma500/framebuffer.h 
b/drivers/gpu/drm/gma500/framebuffer.h
index 395f20b..50b384e 100644
--- a/drivers/gpu/drm/gma500/framebuffer.h
+++ b/drivers/gpu/drm/gma500/framebuffer.h
@@ -32,6 +32,8 @@ struct psb_framebuffer {
        struct address_space *addr_space;
        struct fb_info *fbdev;
        struct gtt_range *gtt;
+       bool vm_map;
+
 };
 
 struct psb_fbdev {
-- 
2.1.0
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20160906/c5754d69/attachment-0001.html>


More information about the dri-devel mailing list