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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>

---
 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
_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel

[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux