GFX: optimize vmalloc allocation as it's fragmented severely byPVR driver
authorchenlinz <linx.z.chen@intel.com>
Sat, 28 Apr 2012 06:21:11 +0000 (14:21 +0800)
committerbuildbot <buildbot@intel.com>
Mon, 7 May 2012 11:13:19 +0000 (04:13 -0700)
BZ: 31145

GFX allocates lots of 1 page szie vmalloc areas. It causes dramatic
vmalloc fragmentation. Most such small vmalloc areas are created
as PVRSRV_HAP_WRITECOMBINE. We create a special gen_pool based on
a big vmalloc area. Then, allocate all small PVRSRV_HAP_WRITECOMBINE
request from the pool.

Change-Id: Ia38c4cc78e0e716a52cbd3592b2f8bcf099e08c8
Signed-off-by: Yanmin Zhang <yanmin.zhang@intel.com>
Signed-off-by: chenlinz <linx.z.chen@intel.com>
Reviewed-on: http://android.intel.com:8080/46647
Reviewed-by: Jiang, Fei <fei.jiang@intel.com>
Reviewed-by: Tu, Yun <yun.tu@intel.com>
Reviewed-by: Zeng, Li <li.zeng@intel.com>
Reviewed-by: Tong, BoX <box.tong@intel.com>
Tested-by: Tong, BoX <box.tong@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
drivers/staging/mrst/Kconfig
drivers/staging/mrst/pvr/services4/srvkm/env/linux/mm.c
drivers/staging/mrst/pvr/services4/srvkm/env/linux/mm.h

index 1083644..2868ed1 100644 (file)
@@ -12,6 +12,7 @@ config DRM_INTEL_MID
         select FB_CFB_FILLRECT
         select FB_CFB_IMAGEBLIT
         select DRM_KMS_HELPER
+        select GENERIC_ALLOCATOR
         select DRM_TTM
        help
          xxxxxxxxxxxxxxxxxxxxxxxxxx
index 7f12ff5..f18df04 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/sched.h>
+#include <linux/genalloc.h>
 
 #include "img_defs.h"
 #include "services.h"
@@ -186,6 +187,51 @@ static DEBUG_LINUX_MEM_AREA_REC *DebugLinuxMemAreaRecordFind(LinuxMemArea *psLin
 static IMG_VOID DebugLinuxMemAreaRecordRemove(LinuxMemArea *psLinuxMemArea);
 #endif
 
+/*
+ We assume the total area space for PVRSRV_HAP_WRITECOMBINE is fewer than 4MB.
+If it's more than 4MB, it fails over to vmalloc automatically.
+ */
+#define POOL_SIZE      (4*1024*1024)
+static struct gen_pool *pvrsrv_pool_writecombine;
+static char *pool_start;
+
+static void init_pvr_pool(void)
+{
+       pgprot_t PGProtFlags;
+       int ret = -1;
+
+       pvrsrv_pool_writecombine = gen_pool_create(12, -1);
+       if (!pvrsrv_pool_writecombine) {
+               printk(KERN_ERR "%s: create pvrsrv_pool failed\n",
+                               __func__);
+               return ;
+       }
+       PGProtFlags = PGPROT_WC(PAGE_KERNEL);
+       pool_start = __vmalloc(POOL_SIZE, GFP_KERNEL | __GFP_HIGHMEM,
+                       PGProtFlags);
+
+       if (!pool_start) {
+               printk(KERN_ERR "%s:No vm space to create POOL\n",
+                               __func__);
+               gen_pool_destroy(pvrsrv_pool_writecombine);
+               pvrsrv_pool_writecombine = NULL;
+               return ;
+       } else {
+               ret = gen_pool_add(pvrsrv_pool_writecombine,
+                               pool_start, POOL_SIZE, -1);
+               if (ret) {
+                       printk(KERN_ERR "%s:could not remainder pool\n",
+                                       __func__);
+                       gen_pool_destroy(pvrsrv_pool_writecombine);
+                       pvrsrv_pool_writecombine = NULL;
+                       vfree(pool_start);
+                       pool_start = NULL;
+                       return ;
+                       }
+               }
+       return ;
+}
+
 PVRSRV_ERROR
 LinuxMMInit(IMG_VOID)
 {
@@ -235,7 +281,8 @@ LinuxMMInit(IMG_VOID)
         return PVRSRV_ERROR_OUT_OF_MEMORY;
     }
 
-    return PVRSRV_OK;
+       init_pvr_pool();
+       return PVRSRV_OK;
 }
 
 #if defined(DEBUG_LINUX_MEM_AREAS)
@@ -583,7 +630,7 @@ LinuxMemArea *
 NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags)
 {
     LinuxMemArea *psLinuxMemArea;
-    IMG_VOID *pvCpuVAddr;
+       IMG_VOID *pvCpuVAddr = NULL;
 
     psLinuxMemArea = LinuxMemAreaStructAlloc();
     if(!psLinuxMemArea)
@@ -591,7 +638,20 @@ NewVMallocLinuxMemArea(IMG_UINT32 ui32Bytes, IMG_UINT32 ui32AreaFlags)
         goto failed;
     }
 
-    pvCpuVAddr = VMallocWrapper(ui32Bytes, ui32AreaFlags);
+       psLinuxMemArea->bfromPool = IMG_FALSE;
+       if (pvrsrv_pool_writecombine && ui32Bytes <= 128*1024) {
+               if ((ui32AreaFlags & PVRSRV_HAP_CACHETYPE_MASK) ==
+                               PVRSRV_HAP_WRITECOMBINE) {
+                       pvCpuVAddr = gen_pool_alloc(pvrsrv_pool_writecombine,
+                                       PAGE_ALIGN(ui32Bytes));
+                       if (pvCpuVAddr)
+                               psLinuxMemArea->bfromPool = IMG_TRUE;
+           }
+       }
+
+       if (!pvCpuVAddr)
+               pvCpuVAddr = VMallocWrapper(ui32Bytes, ui32AreaFlags);
+
     if(!pvCpuVAddr)
     {
         goto failed;
@@ -644,7 +704,12 @@ FreeVMallocLinuxMemArea(LinuxMemArea *psLinuxMemArea)
 
     PVR_DPF((PVR_DBG_MESSAGE,"%s: pvCpuVAddr: %p",
              __FUNCTION__, psLinuxMemArea->uData.sVmalloc.pvVmallocAddress));
-    VFreeWrapper(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress);
+       if (psLinuxMemArea->bfromPool) {
+               gen_pool_free(pvrsrv_pool_writecombine,
+                               psLinuxMemArea->uData.sVmalloc.pvVmallocAddress,
+                               PAGE_ALIGN(psLinuxMemArea->ui32ByteSize));
+       } else
+               VFreeWrapper(psLinuxMemArea->uData.sVmalloc.pvVmallocAddress);
 
     LinuxMemAreaStructFree(psLinuxMemArea);
 }
index 0fb0917..03f2827 100644 (file)
@@ -149,6 +149,7 @@ struct _LinuxMemArea {
 
     IMG_BOOL bNeedsCacheInvalidate;
 
+    IMG_BOOL bfromPool;
 
     struct list_head   sMMapItem;