RK3368 GPU version: Rogue L 0.17
authorzxl <zhuangxl@rock-chips.com>
Tue, 2 Jun 2015 08:07:27 +0000 (16:07 +0800)
committerzxl <zhuangxl@rock-chips.com>
Tue, 2 Jun 2015 08:07:27 +0000 (16:07 +0800)
1. Support gpu disable dvfs case.
2. Add rk_tf_check_version to compatible for rk3328.
3. merge 1.4_ED3573678 DDK code.
   Tip: Need update RK3368 GPU so version to L0.17(@vendor/rockchip/common).

32 files changed:
drivers/gpu/rogue/build/linux/config/core.mk
drivers/gpu/rogue/config_kernel.h
drivers/gpu/rogue/hwdefs/km/configs/rgxconfig_km_4.V.2.51.h
drivers/gpu/rogue/hwdefs/km/rgx_cr_defs_km.h
drivers/gpu/rogue/include/pvrversion.h
drivers/gpu/rogue/kernel/drivers/staging/imgtec/adf_pdp.c
drivers/gpu/rogue/kernel/drivers/staging/imgtec/pvr_sync.c
drivers/gpu/rogue/services/server/common/process_stats.c
drivers/gpu/rogue/services/server/common/pvrsrv.c
drivers/gpu/rogue/services/server/common/resman.c
drivers/gpu/rogue/services/server/devices/rgx/rgxdebug.c
drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.c
drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.h
drivers/gpu/rogue/services/server/env/linux/mmap.c
drivers/gpu/rogue/services/server/env/linux/module.c
drivers/gpu/rogue/services/server/env/linux/osfunc.c
drivers/gpu/rogue/services/server/env/linux/ossecure_export.c
drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.c
drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.h [new file with mode: 0644]
drivers/gpu/rogue/services/server/env/linux/pvr_bridge_k.c
drivers/gpu/rogue/services/server/env/linux/pvr_debug.c
drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.c
drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.h
drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.c
drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.h
drivers/gpu/rogue/services/server/include/osfunc.h
drivers/gpu/rogue/services/server/include/pvrsrv.h
drivers/gpu/rogue/services/server/include/resman.h
drivers/gpu/rogue/services/shared/common/devicemem.c
drivers/gpu/rogue/services/system/rgx_tc/apollo_flasher_linux.c
drivers/gpu/rogue/system/rk3368/rk_init.c
drivers/gpu/rogue/system/rk3368/rk_init.h

index ddfef85461565fc449d41c40d335f45cb12efa3f..e2abc54b4a513cca94e0c5df5bf89a8a2215f680 100644 (file)
@@ -695,8 +695,15 @@ Enable automatic decoding of Firmware Trace via DebugFS._\
 ))
 
 $(eval $(call TunableKernelConfigC,PVR_LINUX_PYSMEM_MAX_POOL_PAGES,"$(MAX_POOL_PAGES)"))
-$(eval $(call TunableKernelConfigC,PVR_LINUX_VMALLOC_ALLOCATION_THRESHOLD, 16384 ))
 
+# ARM-Linux specific: 
+# When allocating uncached or write-combine memory we need to invalidate the
+# CPU cache before we can use the acquired pages. 
+# The threshhold defines at which number of pages we want to do a full 
+# cache flush instead of invalidating pages one by one.
+$(eval $(call TunableKernelConfigC,PVR_LINUX_ARM_PAGEALLOC_FLUSH_THRESHOLD, 256))
+
+$(eval $(call TunableKernelConfigC,PVR_LINUX_VMALLOC_ALLOCATION_THRESHOLD, 16384 ))
 
 # Tunable RGX_MAX_TA_SYNCS / RGX_MAX_3D_SYNCS to increase the size of sync array in the DDK
 # If defined, these macros take up the values as defined in the environment,
index 18168ff53db60c92ae3a53bd43050a5aaf0598ab..c00d1985435b2c9a8e6bc926042213b89ba1ee91 100644 (file)
@@ -28,6 +28,7 @@
 #define LDM_PLATFORM 
 #define PVRSRV_ENABLE_PROCESS_STATS 
 #define PVR_LINUX_PYSMEM_MAX_POOL_PAGES 10240
+#define PVR_LINUX_ARM_PAGEALLOC_FLUSH_THRESHOLD  256
 #define PVR_LINUX_VMALLOC_ALLOCATION_THRESHOLD  16384 
 #define ANDROID 
 #define PVR_ANDROID_NATIVE_WINDOW_HAS_SYNC 
index 6464e705d7ae4a5d83b49aefae06e44e40ba9cb6..771dd6b418cafb2256cd1571ea7f835027b08ebc 100644 (file)
@@ -42,8 +42,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #ifndef _RGXCONFIG_KM_4_V_2_51_H_
 #define _RGXCONFIG_KM_4_V_2_51_H_
 
-/***** Automatically generated file (11/24/2014 2:08:59 PM): Do not edit manually ********************/
-/***** Timestamp:  (11/24/2014 2:08:59 PM)************************************************************/
+/***** Automatically generated file (3/5/2015 11:29:38 AM): Do not edit manually ********************/
+/***** Timestamp:  (3/5/2015 11:29:38 AM)************************************************************/
 
 #define RGX_BNC_KM_B 4
 #define RGX_BNC_KM_N 2
@@ -59,11 +59,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define RGX_FEATURE_CLUSTER_GROUPING 
 #define RGX_FEATURE_SLC_CACHE_LINE_SIZE_BITS (512)
 #define RGX_FEATURE_VIRTUAL_ADDRESS_SPACE_BITS (40)
+#define RGX_FEATURE_TLA 
 #define RGX_FEATURE_GS_RTA_SUPPORT 
 #define RGX_FEATURE_NUM_ISP_IPP_PIPES (8)
 #define RGX_FEATURE_META (LTP218)
 #define RGX_FEATURE_XT_TOP_INFRASTRUCTURE 
+#define RGX_FEATURE_FBCDC_ARCHITECTURE (2)
 #define RGX_FEATURE_META_COREMEM_SIZE (32)
+#define RGX_FEATURE_COMPUTE 
 
 
 #endif /* _RGXCONFIG_4_V_2_51_H_ */
index 463a5ad6b6209346ad220023997384e243580000..7ca15eceb94f3ae2a128c2bb3460ffb3de68f136 100644 (file)
@@ -2255,6 +2255,34 @@ Data master value to be used for fence requests
 #define RGX_CR_GARTEN_SLC_FORCE_COHERENCY_CLRMSK          (0XFFFFFFFEU)
 #define RGX_CR_GARTEN_SLC_FORCE_COHERENCY_EN              (0X00000001U)
 
+/*
+    Register RGX_CR_BIF_MMU_ENTRY_STATUS
+*/
+#define RGX_CR_BIF_MMU_ENTRY_STATUS                       (0x1288U)
+#define RGX_CR_BIF_MMU_ENTRY_STATUS_MASKFULL              (IMG_UINT64_C(0x000000FFFFFFF0F3))
+
+#define RGX_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_SHIFT         (12U)
+#define RGX_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_CLRMSK        (IMG_UINT64_C(0XFFFFFF0000000FFF))
+
+#define RGX_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_SHIFT        (4U)
+#define RGX_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_CLRMSK       (IMG_UINT64_C(0XFFFFFFFFFFFFFF0F))
+
+#define RGX_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_SHIFT       (0U)
+#define RGX_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_CLRMSK      (IMG_UINT64_C(0XFFFFFFFFFFFFFFFC))
+
+/*
+    Register RGX_CR_BIF_MMU_ENTRY
+*/
+#define RGX_CR_BIF_MMU_ENTRY                              (0x1290U)
+#define RGX_CR_BIF_MMU_ENTRY_MASKFULL                     (IMG_UINT64_C(0x0000000000000003))
+
+#define RGX_CR_BIF_MMU_ENTRY_ENABLE_SHIFT                 (1U)
+#define RGX_CR_BIF_MMU_ENTRY_ENABLE_CLRMSK                (0XFFFFFFFDU)
+#define RGX_CR_BIF_MMU_ENTRY_ENABLE_EN                    (0X00000002U)
+
+#define RGX_CR_BIF_MMU_ENTRY_PENDING_SHIFT                (0U)
+#define RGX_CR_BIF_MMU_ENTRY_PENDING_CLRMSK               (0XFFFFFFFEU)
+#define RGX_CR_BIF_MMU_ENTRY_PENDING_EN                   (0X00000001U)
 
 /*
  Index registers per data master. Byte aligned fields to allow byte-masked access 
index 24c08f8d35f0d83122c6d8df76df5f4572143656..f763ca080be45b444a0800c846fbeb747682262b 100755 (executable)
@@ -45,6 +45,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #ifndef _PVRVERSION_H_
 #define _PVRVERSION_H_
 
+/*
+ *  Rogue KM Version Note
+ *
+ *  L 0.16:
+ *          Support gpu disable dvfs case.
+ *          Add rk_tf_check_version to compatible for rk3328.
+ *  L 0.17:
+ *          merge 1.4_ED3573678 DDK code
+ */
+
 #define PVR_STR(X) #X
 #define PVR_STR2(X) PVR_STR(X)
 
@@ -53,7 +63,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define PVRVERSION_FAMILY           "rogueddk"
 #define PVRVERSION_BRANCHNAME       "1.4"
-#define PVRVERSION_BUILD             3443629
+#define PVRVERSION_BUILD             3573678
 #define PVRVERSION_BSCONTROL        "Rogue_DDK_Android_RSCompute"
 
 #define PVRVERSION_STRING           "Rogue_DDK_Android_RSCompute rogueddk 1.4@" PVR_STR2(PVRVERSION_BUILD)
@@ -61,8 +71,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define COPYRIGHT_TXT               "Copyright (c) Imagination Technologies Ltd. All Rights Reserved."
 
-#define PVRVERSION_BUILD_HI          344
-#define PVRVERSION_BUILD_LO          3629
+#define PVRVERSION_BUILD_HI          357
+#define PVRVERSION_BUILD_LO          3678
 #define PVRVERSION_STRING_NUMERIC    PVR_STR2(PVRVERSION_MAJ) "." PVR_STR2(PVRVERSION_MIN) "." PVR_STR2(PVRVERSION_BUILD_HI) "." PVR_STR2(PVRVERSION_BUILD_LO)
 
 #define PVRVERSION_PACK(MAJ,MIN) ((((MAJ)&0xFFFF) << 16) | (((MIN)&0xFFFF) << 0))
@@ -70,5 +80,5 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define PVRVERSION_UNPACK_MIN(VERSION) (((VERSION) >> 0) & 0xFFFF)
 
 //chenli:define rockchip version
-#define RKVERSION                   "Rogue L 0.15"
+#define RKVERSION                   "Rogue L 0.17"
 #endif /* _PVRVERSION_H_ */
index 8a325e14557bf9574b2ed49a173b24ff00bcc898..1dd4f9e578be99c56cbf6739aae9229d68056fe6 100644 (file)
@@ -462,6 +462,36 @@ static bool pdp_vsync_triggered(struct adf_pdp_device *pdp)
        return atomic_read(&pdp->vsync_triggered) == 1;
 }
 
+static void pdp_enable_vsync(struct adf_pdp_device *pdp)
+{
+       int err = 0;
+       u32 reg_value = pdp_read_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB);
+       reg_value |= (0x1 << INTEN_VBLNK1_SHIFT);
+       pdp_write_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB, reg_value);
+
+       err = apollo_enable_interrupt(&pdp->pdata->pdev->dev,
+               APOLLO_INTERRUPT_PDP);
+       if (err) {
+               dev_err(&pdp->pdev->dev,
+                       "apollo_enable_interrupt failed (%d)\n", err);
+       }
+}
+
+static void pdp_disable_vsync(struct adf_pdp_device *pdp)
+{
+       int err = 0;
+       u32 reg_value = pdp_read_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB);
+       reg_value &= ~(0x1 << INTEN_VBLNK1_SHIFT);
+       pdp_write_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB, reg_value);
+
+       err = apollo_disable_interrupt(&pdp->pdata->pdev->dev,
+               APOLLO_INTERRUPT_PDP);
+       if (err) {
+               dev_err(&pdp->pdev->dev,
+                       "apollo_disable_interrupt failed (%d)\n", err);
+       }
+}
+
 static void pdp_post(struct adf_device *adf_dev, struct adf_post *cfg,
        void *driver_state)
 {
@@ -515,17 +545,17 @@ static void pdp_post(struct adf_device *adf_dev, struct adf_post *cfg,
        /* Wait until the buffer is on-screen, so we know the previous buffer
         * has been retired and off-screen.
         *
-        * If vsync was already off when this post was serviced, we don't need
-        * to wait for it (note: this will cause tearing if done when the
-        * display is not blanked).
+        * If vsync was already off when this post was serviced, we need to
+        * enable the vsync again briefly so the register updates we shadowed
+        * above get applied and we don't signal the fence prematurely. One
+        * vsync afterwards, we'll disable the vsync again.
         */
-       if (atomic_read(&pdp->vsync_state)) {
-               if (wait_event_timeout(pdp->vsync_wait_queue,
-                       pdp_vsync_triggered(pdp), timeout) == 0) {
-                       /* Timeout - continue as if vsync was triggered, as
-                        * possible tearing is better than wedging */
-                       dev_err(&pdp->pdev->dev, "Post VSync wait timeout");
-               }
+       if (!atomic_xchg(&pdp->vsync_state, 1))
+               pdp_enable_vsync(pdp);
+
+       if (wait_event_timeout(pdp->vsync_wait_queue,
+               pdp_vsync_triggered(pdp), timeout) == 0) {
+               dev_err(&pdp->pdev->dev, "Post VSync wait timeout");
        }
 }
 
@@ -546,21 +576,6 @@ static bool pdp_supports_event(struct adf_obj *obj, enum adf_event_type type)
        }
 }
 
-static void pdp_disable_vsync(struct adf_pdp_device *pdp)
-{
-       int err = 0;
-       u32 reg_value = pdp_read_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB);
-       reg_value &= ~(0x1 << INTEN_VBLNK1_SHIFT);
-       pdp_write_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB, reg_value);
-
-       err = apollo_disable_interrupt(&pdp->pdata->pdev->dev,
-               APOLLO_INTERRUPT_PDP);
-       if (err) {
-               dev_err(&pdp->pdev->dev,
-                       "apollo_disable_interrupt failed (%d)\n", err);
-       }
-}
-
 static void pdp_irq_handler(void *data)
 {
        struct adf_pdp_device *pdp = data;
@@ -588,21 +603,6 @@ static void pdp_irq_handler(void *data)
        }
 }
 
-static void pdp_enable_vsync(struct adf_pdp_device *pdp)
-{
-       int err = 0;
-       u32 reg_value = pdp_read_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB);
-       reg_value |= (0x1 << INTEN_VBLNK1_SHIFT);
-       pdp_write_reg(pdp, TCF_RGBPDP_PVR_TCF_RGBPDP_INTENAB, reg_value);
-
-       err = apollo_enable_interrupt(&pdp->pdata->pdev->dev,
-               APOLLO_INTERRUPT_PDP);
-       if (err) {
-               dev_err(&pdp->pdev->dev,
-                       "apollo_enable_interrupt failed (%d)\n", err);
-       }
-}
-
 static void pdp_set_event(struct adf_obj *obj, enum adf_event_type type,
        bool enabled)
 {
index 31cab2e359b023b5018f4a5d02580bad9126db35..e00e76fab86fe6c13c29b6c420d2171dcae7edb2 100644 (file)
@@ -1038,6 +1038,10 @@ enum PVRSRV_ERROR pvr_sync_append_fences(
        struct pvr_sync_alloc_data *alloc_sync_data = NULL;
        unsigned i;
 
+       if ((nr_updates && (!update_ufo_addresses || !update_values)) ||
+               (nr_checks && (!check_ufo_addresses || !check_values)))
+               return PVRSRV_ERROR_INVALID_PARAMS;
+
        sync_data =
                kzalloc(sizeof(struct pvr_sync_append_data)
                        + nr_check_fences * sizeof(struct sync_fence*),
@@ -1303,15 +1307,19 @@ enum PVRSRV_ERROR pvr_sync_append_fences(
        sync_data->nr_checks = nr_checks + num_used_sync_checks;
        sync_data->nr_updates = nr_updates + num_used_sync_updates;
        /* Append original check and update sync values/addresses */
-       memcpy(update_address_pos, update_ufo_addresses,
-               sizeof(PRGXFWIF_UFO_ADDR) * nr_updates);
-       memcpy(update_value_pos, update_values,
-               sizeof(u32) * nr_updates);
-
-       memcpy(check_address_pos, check_ufo_addresses,
-               sizeof(PRGXFWIF_UFO_ADDR) * nr_checks);
-       memcpy(check_value_pos, check_values,
-               sizeof(u32) * nr_checks);
+       if (update_ufo_addresses)
+               memcpy(update_address_pos, update_ufo_addresses,
+                          sizeof(PRGXFWIF_UFO_ADDR) * nr_updates);
+       if (update_values)
+               memcpy(update_value_pos, update_values,
+                          sizeof(u32) * nr_updates);
+
+       if (check_ufo_addresses)
+               memcpy(check_address_pos, check_ufo_addresses,
+                          sizeof(PRGXFWIF_UFO_ADDR) * nr_checks);
+       if (check_values)
+               memcpy(check_value_pos, check_values,
+                          sizeof(u32) * nr_checks);
 
        *append_sync_data = sync_data;
 
index d0e4b4d3fab059d143feeffbafe0e2b3ff826b83..79d9f15e7eb66791ee3265ab80d908d652a92deb 100755 (executable)
@@ -215,6 +215,7 @@ typedef struct _PVRSRV_PROCESS_STATS_ {
        /* OS level process ID */
        IMG_PID                           pid;
        IMG_UINT32                        ui32RefCount;
+       IMG_UINT32                        ui32MemRefCount;
 
        /* Folder name used to store the statistic */
        IMG_CHAR                                          szFolderName[MAX_PROC_NAME_LENGTH];
@@ -232,6 +233,7 @@ typedef struct _PVRSRV_PROCESS_STATS_ {
 
        struct _PVRSRV_MEMORY_STATS_*     psMemoryStats;
        struct _PVRSRV_RI_MEMORY_STATS_*  psRIMemoryStats;
+
 } PVRSRV_PROCESS_STATS;
 
 typedef struct _PVRSRV_RENDER_STATS_ {
@@ -364,13 +366,15 @@ static PVRSRV_GLOBAL_MEMORY_STATS gsGlobalStats;
 #define HASH_INITIAL_SIZE 5
 static HASH_TABLE* gpsTrackingTable;
 
+static IMG_UINT32 _PVRSRVIncrMemStatRefCount(IMG_PVOID pvStatPtr);
+static IMG_UINT32 _PVRSRVDecrMemStatRefCount(IMG_PVOID pvStatPtr);
+
 static IMG_BOOL
 _PVRSRVGetGlobalMemStat(IMG_PVOID pvStatPtr, 
                                                IMG_UINT32 ui32StatNumber, 
                                                IMG_INT32* pi32StatData, 
                                                IMG_CHAR** ppszStatFmtText);
 
-
 IMG_VOID InsertPowerTimeStatistic(PVRSRV_POWER_ENTRY_TYPE bType,
                IMG_INT32 i32CurrentState, IMG_INT32 i32NextState,
         IMG_UINT64 ui64SysStartTime, IMG_UINT64 ui64SysEndTime,
@@ -480,9 +484,6 @@ _DestoryRenderStat(PVRSRV_RENDER_STATS* psRenderStats)
 {
        PVR_ASSERT(psRenderStats != IMG_NULL);
 
-       /* Remove the statistic from the OS... */
-       OSRemoveStatisticEntry(psRenderStats->pvOSData);
-
        /* Free the memory... */
        OSFreeMem(psRenderStats);
 } /* _DestoryRenderStat */
@@ -667,28 +668,35 @@ _CreateOSStatisticEntries(PVRSRV_PROCESS_STATS* psProcessStats,
        psProcessStats->pvOSPidEntryData  = OSCreateStatisticEntry("process_stats",
                                                                   psProcessStats->pvOSPidFolderData,
                                                                   PVRSRVStatsObtainElement,
+                                                                                                                          _PVRSRVIncrMemStatRefCount,
+                                                                                                                          _PVRSRVDecrMemStatRefCount,
                                                                   (IMG_PVOID) psProcessStats);
-
        if (pvOSPowerStatsEntryData==NULL)
        {
-        pvOSPowerStatsEntryData  = OSCreateStatisticEntry("power_timings_stats",
+               pvOSPowerStatsEntryData  = OSCreateStatisticEntry("power_timings_stats",
                                                                                                        NULL,
                                                                                                        PVRSRVPowerStatsObtainElement,
-                                                           (IMG_PVOID) psProcessStats);
+                                                                                                       IMG_NULL,
+                                                                                                       IMG_NULL,
+                                                                                                       (IMG_PVOID) psProcessStats);
        }
 
 #if defined(PVRSRV_ENABLE_MEMORY_STATS)
        psProcessStats->psMemoryStats->pvOSMemEntryData = OSCreateStatisticEntry("mem_area",
                                                                   psProcessStats->pvOSPidFolderData,
                                                                   PVRSRVStatsObtainElement,
-                                                                  (IMG_PVOID) psProcessStats->psMemoryStats);
+                                                                                                                          IMG_NULL,
+                                                                                                                          IMG_NULL,
+                                                                                                                          (IMG_PVOID) psProcessStats->psMemoryStats);
 #endif
 
 #if defined(PVR_RI_DEBUG)
        psProcessStats->psRIMemoryStats->pvOSRIMemEntryData = OSCreateStatisticEntry("ri_mem_area",
                                                                   psProcessStats->pvOSPidFolderData,
                                                                   PVRSRVStatsObtainElement,
-                                                                  (IMG_PVOID) psProcessStats->psRIMemoryStats);
+                                                                                                                          IMG_NULL,
+                                                                                                                          IMG_NULL,
+                                                                                                                          (IMG_PVOID) psProcessStats->psRIMemoryStats);
 #endif
 } /* _CreateOSStatisticEntries */
 
@@ -704,14 +712,18 @@ _RemoveOSStatisticEntries(PVRSRV_PROCESS_STATS* psProcessStats)
        PVR_ASSERT(psProcessStats != IMG_NULL);
 
 #if defined(PVR_RI_DEBUG)
+       PVR_ASSERT(psProcessStats->psRIMemoryStats->pvOSRIMemEntryData != IMG_NULL);
        OSRemoveStatisticEntry(psProcessStats->psRIMemoryStats->pvOSRIMemEntryData);
 #endif
 
 #if defined(PVRSRV_ENABLE_MEMORY_STATS)
+       PVR_ASSERT(psProcessStats->psMemoryStats->pvOSMemEntryData != IMG_NULL);
        OSRemoveStatisticEntry(psProcessStats->psMemoryStats->pvOSMemEntryData);
 #endif
 
+       PVR_ASSERT(psProcessStats->pvOSPidEntryData != IMG_NULL);
        OSRemoveStatisticEntry(psProcessStats->pvOSPidEntryData);
+       PVR_ASSERT(psProcessStats->pvOSPidFolderData != IMG_NULL);
        OSRemoveStatisticFolder(psProcessStats->pvOSPidFolderData);
 } /* _RemoveOSStatisticEntries */
 
@@ -726,9 +738,6 @@ _DestoryProcessStat(PVRSRV_PROCESS_STATS* psProcessStats)
 {
        PVR_ASSERT(psProcessStats != IMG_NULL);
 
-       /* Remove this statistic from the OS... */
-       _RemoveOSStatisticEntries(psProcessStats);
-
        /* Free the live and dead render statistic lists... */
        while (psProcessStats->psRenderLiveList != IMG_NULL)
        {
@@ -748,17 +757,77 @@ _DestoryProcessStat(PVRSRV_PROCESS_STATS* psProcessStats)
 
        /* Free the memory statistics... */
 #if defined(PVRSRV_ENABLE_MEMORY_STATS)
-       while (psProcessStats->psMemoryStats->psMemoryRecords)
+       if (psProcessStats->psMemoryStats != IMG_NULL)
+       {
+               while (psProcessStats->psMemoryStats->psMemoryRecords)
+               {
+                       List_PVRSRV_MEM_ALLOC_REC_Remove(psProcessStats->psMemoryStats->psMemoryRecords);
+               }
+               OSMemSet(psProcessStats->psMemoryStats, 0x6b, sizeof(PVRSRV_MEMORY_STATS));
+               OSFreeMem(psProcessStats->psMemoryStats);
+               psProcessStats->psMemoryStats = IMG_NULL;
+       }
+#endif
+
+#if defined(PVR_RI_DEBUG)
+       if (psProcessStats->psRIMemoryStats != IMG_NULL)
        {
-               List_PVRSRV_MEM_ALLOC_REC_Remove(psProcessStats->psMemoryStats->psMemoryRecords);
+               OSFreeMem(psProcessStats->psRIMemoryStats);
+               psProcessStats->psRIMemoryStats = IMG_NULL;
        }
-       OSFreeMem(psProcessStats->psMemoryStats);
 #endif
 
        /* Free the memory... */
        OSFreeMem(psProcessStats);
 } /* _DestoryProcessStat */
 
+static IMG_UINT32 _PVRSRVIncrMemStatRefCount(IMG_PVOID pvStatPtr)
+{
+       PVRSRV_STAT_STRUCTURE_TYPE*  peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
+       PVRSRV_PROCESS_STATS*  psProcessStats = (PVRSRV_PROCESS_STATS*) pvStatPtr;
+       IMG_UINT32 ui32Res = 7777;
+
+       switch (*peStructureType)
+       {
+               case PVRSRV_STAT_STRUCTURE_PROCESS:
+               {
+                       /* Increment stat memory refCount */
+                       ui32Res = ++psProcessStats->ui32MemRefCount;
+                       break;
+               }
+               default:
+               {
+                       break;
+               }
+       }
+       return ui32Res;
+}
+
+static IMG_UINT32 _PVRSRVDecrMemStatRefCount(IMG_PVOID pvStatPtr)
+{
+       PVRSRV_STAT_STRUCTURE_TYPE*  peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
+       PVRSRV_PROCESS_STATS*  psProcessStats = (PVRSRV_PROCESS_STATS*) pvStatPtr;
+       IMG_UINT32 ui32Res = 7777;
+
+       switch (*peStructureType)
+       {
+               case PVRSRV_STAT_STRUCTURE_PROCESS:
+               {
+                       /* Decrement stat memory refCount and free if now zero */
+                       ui32Res = --psProcessStats->ui32MemRefCount;
+                       if (ui32Res == 0)
+                       {
+                               _DestoryProcessStat(psProcessStats);
+                       }
+                       break;
+               }
+               default:
+               {
+                       break;
+               }
+       }
+       return ui32Res;
+}
 
 /*************************************************************************/ /*!
 @Function       _CompressMemoryUsage
@@ -806,7 +875,8 @@ _CompressMemoryUsage(IMG_VOID)
                PVRSRV_PROCESS_STATS*  psNextProcessStats = psProcessStatsToBeFreed->psNext;
 
                psProcessStatsToBeFreed->psNext = IMG_NULL;
-               _DestoryProcessStat(psProcessStatsToBeFreed);
+               _RemoveOSStatisticEntries(psProcessStatsToBeFreed);
+               _PVRSRVDecrMemStatRefCount((void*)psProcessStatsToBeFreed);
 
                psProcessStatsToBeFreed = psNextProcessStats;
        }
@@ -863,6 +933,8 @@ PVRSRVStatsInitialise(IMG_VOID)
        pvOSGlobalMemEntryRef = OSCreateStatisticEntry(pszDriverStatFilename,
                                                                                                   IMG_NULL,
                                                                                                   _PVRSRVGetGlobalMemStat,
+                                                                                                  IMG_NULL,
+                                                                                                  IMG_NULL,
                                                                                                   IMG_NULL);
 
        OSMemSet(&gsGlobalStats, 0, sizeof(gsGlobalStats));
@@ -908,20 +980,20 @@ PVRSRVStatsDestroy(IMG_VOID)
        }
 
        /* Free the live and dead lists... */
-    while (psLiveList != IMG_NULL)
+       while (psLiveList != IMG_NULL)
     {
                PVRSRV_PROCESS_STATS*  psProcessStats = psLiveList;
 
                _RemoveProcessStatsFromList(psProcessStats);
-               _DestoryProcessStat(psProcessStats);
+               _RemoveOSStatisticEntries(psProcessStats);
        }
-
-    while (psDeadList != IMG_NULL)
+       while (psDeadList != IMG_NULL)
     {
                PVRSRV_PROCESS_STATS*  psProcessStats = psDeadList;
 
                _RemoveProcessStatsFromList(psProcessStats);
-               _DestoryProcessStat(psProcessStats);
+
+               _RemoveOSStatisticEntries(psProcessStats);
        }
 
        /* Remove the OS folders used by the PID folders... */
@@ -938,7 +1010,6 @@ PVRSRVStatsDestroy(IMG_VOID)
 } /* PVRSRVStatsDestroy */
 
 
-
 static void _decrease_global_stat(PVRSRV_MEM_ALLOC_TYPE eAllocType,
                                                                  IMG_SIZE_T uiBytes)
 {
@@ -1219,6 +1290,7 @@ PVRSRVStatsRegisterProcess(IMG_HANDLE* phProcessStats)
        psProcessStats->eStructureType  = PVRSRV_STAT_STRUCTURE_PROCESS;
        psProcessStats->pid             = currentPid;
        psProcessStats->ui32RefCount    = 1;
+       psProcessStats->ui32MemRefCount = 1;
 
        psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_CONNECTIONS]     = 1;
        psProcessStats->i32StatValue[PVRSRV_PROCESS_STAT_TYPE_MAX_CONNECTIONS] = 1;
@@ -2458,10 +2530,12 @@ IMG_BOOL
 PVRSRVStatsObtainElement(IMG_PVOID pvStatPtr, IMG_UINT32 ui32StatNumber,
                          IMG_INT32* pi32StatData, IMG_CHAR** ppszStatFmtText)
 {
+       IMG_BOOL bRes = IMG_FALSE;
        PVRSRV_STAT_STRUCTURE_TYPE*  peStructureType = (PVRSRV_STAT_STRUCTURE_TYPE*) pvStatPtr;
 
        if (peStructureType == IMG_NULL  ||  pi32StatData == IMG_NULL)
        {
+               PVR_DPF((PVR_DBG_ERROR, "%s: Invalid param, peStructureType=<%p>, pvStatPtr=<%p>", __FUNCTION__, (void*)peStructureType, (void*)pvStatPtr));
                return IMG_FALSE;
        }
 
@@ -2469,16 +2543,18 @@ PVRSRVStatsObtainElement(IMG_PVOID pvStatPtr, IMG_UINT32 ui32StatNumber,
        {
                PVRSRV_PROCESS_STATS*  psProcessStats = (PVRSRV_PROCESS_STATS*) pvStatPtr;
 
-               return _ObtainProcessStatistic(psProcessStats, ui32StatNumber,
+               bRes = _ObtainProcessStatistic(psProcessStats, ui32StatNumber,
                                                                           pi32StatData, ppszStatFmtText);
+               return bRes;
        }
 #if defined(PVRSRV_ENABLE_MEMORY_STATS)
        else if (*peStructureType == PVRSRV_STAT_STRUCTURE_MEMORY)
        {
                PVRSRV_MEMORY_STATS*  psMemoryStats = (PVRSRV_MEMORY_STATS*) pvStatPtr;
 
-               return _ObtainMemoryStatistic(psMemoryStats, ui32StatNumber,
+               bRes = _ObtainMemoryStatistic(psMemoryStats, ui32StatNumber,
                                                                          pi32StatData, ppszStatFmtText);
+               return bRes;
        }
 #endif
 #if defined(PVR_RI_DEBUG)
@@ -2486,13 +2562,15 @@ PVRSRVStatsObtainElement(IMG_PVOID pvStatPtr, IMG_UINT32 ui32StatNumber,
        {
                PVRSRV_RI_MEMORY_STATS*  psRIMemoryStats = (PVRSRV_RI_MEMORY_STATS*) pvStatPtr;
 
-               return _ObtainRIMemoryStatistic(psRIMemoryStats, ui32StatNumber,
+               bRes = _ObtainRIMemoryStatistic(psRIMemoryStats, ui32StatNumber,
                                                                            pi32StatData, ppszStatFmtText);
+               return bRes;
        }
 #endif
-
-       /* Stat type not handled probably indicates bad pointers... */
-       PVR_ASSERT(IMG_FALSE);
+       else
+       {
+               PVR_DPF((PVR_DBG_ERROR, "%s: Unrecognised peStructureType<%p>=%d", __FUNCTION__, (void*)peStructureType, *peStructureType));
+       }
 
        return IMG_FALSE;
 } /* PVRSRVStatsObtainElement */
@@ -2538,6 +2616,7 @@ IMG_BOOL PVRSRVPowerStatsObtainElement(IMG_PVOID pvStatPtr, IMG_UINT32 ui32StatN
     if (peStructureType == IMG_NULL  ||  pi32StatData == IMG_NULL)
        {
                /* Stat type not handled probably indicates bad pointers... */
+               PVR_DPF((PVR_DBG_ERROR, "%s: Invalid param, peStructureType=<%p>, pvStatPtr=<%p>, ppszStatFmtText=<%p>, *ppszStatFmtText=<%p>", __FUNCTION__, (void*)peStructureType, (void*)pvStatPtr, (void*)ppszStatFmtText, (void*)*ppszStatFmtText));
                PVR_ASSERT(IMG_FALSE);
                return IMG_FALSE;
        }
@@ -2552,25 +2631,53 @@ IMG_BOOL PVRSRVPowerStatsObtainElement(IMG_PVOID pvStatPtr, IMG_UINT32 ui32StatN
         case PVRSRV_POWER_TIMING_STAT_PRE_DEVICE:
         {
             (*ppszStatFmtText)="Pre-Device: %u\n";
-            (*pi32StatData)= ((IMG_UINT32)(ui64ForcedPreDevice)/(IMG_UINT32) ui64TotalForcedEntries);
+                       if (ui64TotalForcedEntries > 0)
+                       {
+                               (*pi32StatData)= ((IMG_UINT32)(ui64ForcedPreDevice)/(IMG_UINT32) ui64TotalForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_PRE_SYSTEM:
         {
             (*ppszStatFmtText)="Pre-System: %u\n";
-            (*pi32StatData)=((IMG_UINT32)(ui64ForcedPreSystem)/(IMG_UINT32) ui64TotalForcedEntries);
+                       if (ui64TotalForcedEntries > 0)
+                       {
+                               (*pi32StatData)=((IMG_UINT32)(ui64ForcedPreSystem)/(IMG_UINT32) ui64TotalForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_POST_DEVICE:
         {
             (*ppszStatFmtText)="Post-Device: %u\n";
-            (*pi32StatData)=((IMG_UINT32)(ui64ForcedPostDevice)/(IMG_UINT32) ui64TotalForcedEntries);
+                       if (ui64TotalForcedEntries > 0)
+                       {
+                               (*pi32StatData)=((IMG_UINT32)(ui64ForcedPostDevice)/(IMG_UINT32) ui64TotalForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_POST_SYSTEM:
         {
             (*ppszStatFmtText)="Post-System: %u\n";
-            (*pi32StatData)=((IMG_UINT32)(ui64ForcedPostSystem)/(IMG_UINT32) ui64TotalForcedEntries);
+                       if (ui64TotalForcedEntries > 0)
+                       {
+                               (*pi32StatData)=((IMG_UINT32)(ui64ForcedPostSystem)/(IMG_UINT32) ui64TotalForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_NEWLINE1:
@@ -2587,25 +2694,53 @@ IMG_BOOL PVRSRVPowerStatsObtainElement(IMG_PVOID pvStatPtr, IMG_UINT32 ui32StatN
         case PVRSRV_POWER_TIMING_STAT_NON_PRE_DEVICE:
         {
             (*ppszStatFmtText)="Pre-Device: %u\n";
-            (*pi32StatData)=((IMG_UINT32)(ui64NotForcedPreDevice)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       if (ui64TotalNotForcedEntries > 0)
+                       {
+                               (*pi32StatData)=((IMG_UINT32)(ui64NotForcedPreDevice)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_NON_PRE_SYSTEM:
         {
             (*ppszStatFmtText)="Pre-System: %u\n";
-            (*pi32StatData)=((IMG_UINT32)(ui64NotForcedPreSystem)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       if (ui64TotalNotForcedEntries > 0)
+                       {
+                               (*pi32StatData)=((IMG_UINT32)(ui64NotForcedPreSystem)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_NON_POST_DEVICE:
         {
             (*ppszStatFmtText)="Post-Device: %u\n";
-            (*pi32StatData)= ((IMG_UINT32)(ui64NotForcedPostDevice)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       if (ui64TotalNotForcedEntries > 0)
+                       {
+                               (*pi32StatData)= ((IMG_UINT32)(ui64NotForcedPostDevice)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_NON_POST_SYSTEM:
         {
             (*ppszStatFmtText)="Post-System: %u\n";
-            (*pi32StatData)=((IMG_UINT32)(ui64NotForcedPostSystem)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       if (ui64TotalNotForcedEntries > 0)
+                       {
+                               (*pi32StatData)=((IMG_UINT32)(ui64NotForcedPostSystem)/(IMG_UINT32) ui64TotalNotForcedEntries);
+                       }
+                       else
+                       {
+                               (*pi32StatData)= 0;
+                       }
             break;
         }
         case PVRSRV_POWER_TIMING_STAT_FW_BOOTUP_TIME:
index c642bda8f87b2d86ae4a6c5aae2bedead49f12d8..fdad3ef8d64da0c48bef7f4f0724724e10c36dcc 100644 (file)
@@ -371,6 +371,9 @@ static IMG_VOID CleanupThread(IMG_PVOID pvData)
        PVRSRV_ERROR eRc;
        IMG_UINT64   ui64TimesliceLimit;
 
+       /* Store the process id (pid) of the clean-up thread */
+       psPVRSRVData->cleanupThreadPid = OSGetCurrentProcessIDKM();
+
        PVR_DPF((CLEANUP_DPFL, "CleanupThread: thread starting... "));
 
        /* Open an event on the clean up event object so we can listen on it,
index c23db6135d18d60ab3b4ca4ea07cbc5eb76df028..4ef15944ae82d7ad6b18b1b9ca9dfa0324f95ca5 100644 (file)
@@ -126,6 +126,14 @@ static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psContext,
 static IMG_VOID ResManFreeResources(PRESMAN_CONTEXT psResManContext);
 static IMG_VOID ResManDeferResources(PRESMAN_CONTEXT psResManContext);
 
+/* list of deferred work passed back from cleanup callbacks, to be called
+ * with the bridge lock released.
+ * This is a list because a single cleanup callback may
+ * generate multiple additional callbacks to be run without
+ * the bridge lock held.
+ */
+static DECLARE_DLLIST(gsFreeOSPagesWorkList);
+
 /*!
 ******************************************************************************
 
@@ -818,6 +826,58 @@ static IMG_VOID* FreeResourceByCriteria_AnyVaCb(RESMAN_ITEM *psCurItem, va_list
        }
 }
 
+/*!
+******************************************************************************
+ @Function      PVRSRVResManAddNoBridgeLockCallback
+
+ @Description
+                Called from resman callback cleanup functions. Adds a function
+               callback to be called without the bridge lock held.
+
+ @inputs        psCallbackInfo - the callback function and callback data parameter
+
+ @Return        None
+**************************************************************************/
+IMG_VOID PVRSRVResManAddNoBridgeLockCallback(RESMAN_FREE_FN_AND_DATA *psCallbackInfo)
+{
+       dllist_add_to_tail(&gsFreeOSPagesWorkList, &psCallbackInfo->sNode);
+}
+
+/*!
+******************************************************************************
+ @Function      PVRSRVResManInDeferredCleanup
+
+ @Description
+                Indicates whether resman is currently in a deferred cleanup call.
+
+ @Return        IMG_BOOL - IMG_TRUE if resman is currently in a deferred cleanup call.
+**************************************************************************/
+IMG_BOOL PVRSRVResManInDeferredCleanup(IMG_VOID)
+{
+       PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
+       return OSGetCurrentProcessIDKM() == psPVRSRVData->cleanupThreadPid;
+}
+
+static IMG_BOOL _ResManDeferredCallbackCB(DLLIST_NODE *psNode, IMG_VOID *pvData)
+{
+       RESMAN_FREE_FN_AND_DATA *psCallbackInfo;
+       PVRSRV_ERROR eError;
+       PVR_UNREFERENCED_PARAMETER(pvData);
+
+       psCallbackInfo = IMG_CONTAINER_OF(psNode, RESMAN_FREE_FN_AND_DATA, sNode);
+
+       eError = psCallbackInfo->pfnFree(psCallbackInfo->pvParam);
+
+       if(eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "_ResManDeferredCallbackCB: pfnFree returned error: %u (%s)",
+                                                                       eError,
+                                                                       PVRSRVGETERRORSTRING(eError)));
+       }
+
+       return IMG_TRUE;
+}
+
 /*!
 ******************************************************************************
  @Function             FreeResourceByCriteria
@@ -867,6 +927,24 @@ static PVRSRV_ERROR FreeResourceByCriteria(PRESMAN_CONTEXT psResManContext,
                if (eError == PVRSRV_OK)
                {
                        iu32ItemsCounter++;
+
+                       /* process any cleanup work which needed to be deferred until
+                        * the bridge lock is released
+                        */
+
+                       if(!dllist_is_empty(&gsFreeOSPagesWorkList))
+                       {
+                               OSReleaseBridgeLock();
+
+                               dllist_foreach_node(&gsFreeOSPagesWorkList,
+                                                                       _ResManDeferredCallbackCB,
+                                                                       IMG_NULL);
+
+                               /* work done. empty the list */
+                               dllist_init(&gsFreeOSPagesWorkList);
+
+                               OSAcquireBridgeLock();
+                       }
                }
                else
                {
index b7029fd33c742208c4b0be9635d057fe1b98728d..37486f9915e0fe4e1a6389f9023ec9f740c63b3c 100644 (file)
@@ -492,25 +492,57 @@ static IMG_VOID _RGXDecodeBIFReqTags(RGXDBG_BIF_ID        eBankID,
                case 0xF:
                {
                        pszTagID = "FB_CDC";
+#if defined(RGX_FEATURE_XT_TOP_INFRASTRUCTURE)
                        {
-                               IMG_UINT32 ui32Req = (ui32TagSB >> 2) & 0x3;
-                               IMG_UINT32 ui32MCUSB = ui32TagSB & 0x3;
+                               IMG_UINT32 ui32Req   = (ui32TagSB >> 0) & 0xf;
+                               IMG_UINT32 ui32MCUSB = (ui32TagSB >> 4) & 0x3;
+                               IMG_CHAR* pszReqOrig = "";
 
-                               IMG_CHAR* pszReqId = (ui32TagSB & 0x10)?"FBDC":"FBC";
-                               IMG_CHAR* pszOrig = "";
+                               switch (ui32Req)
+                               {
+                                       case 0x0: pszReqOrig = "FBC Request, originator ZLS"; break;
+                                       case 0x1: pszReqOrig = "FBC Request, originator PBE"; break;
+                                       case 0x2: pszReqOrig = "FBC Request, originator Host"; break;
+                                       case 0x3: pszReqOrig = "FBC Request, originator TLA"; break;
+                                       case 0x4: pszReqOrig = "FBDC Request, originator ZLS"; break;
+                                       case 0x5: pszReqOrig = "FBDC Request, originator MCU"; break;
+                                       case 0x6: pszReqOrig = "FBDC Request, originator Host"; break;
+                                       case 0x7: pszReqOrig = "FBDC Request, originator TLA"; break;
+                                       case 0x8: pszReqOrig = "FBC Request, originator ZLS Requester Fence"; break;
+                                       case 0x9: pszReqOrig = "FBC Request, originator PBE Requester Fence"; break;
+                                       case 0xa: pszReqOrig = "FBC Request, originator Host Requester Fence"; break;
+                                       case 0xb: pszReqOrig = "FBC Request, originator TLA Requester Fence"; break;
+                                       case 0xc: pszReqOrig = "Reserved"; break;
+                                       case 0xd: pszReqOrig = "Reserved"; break;
+                                       case 0xe: pszReqOrig = "FBDC Request, originator FBCDC(Host) Memory Fence"; break;
+                                       case 0xf: pszReqOrig = "FBDC Request, originator FBCDC(TLA) Memory Fence"; break;
+                               }
+                               OSSNPrintf(pszScratchBuf, ui32ScratchBufSize,
+                                          "%s, MCU sideband 0x%X", pszReqOrig, ui32MCUSB);
+                               pszTagSB = pszScratchBuf;
+                       }
+#else
+                       {
+                               IMG_UINT32 ui32Req   = (ui32TagSB >> 2) & 0x7;
+                               IMG_UINT32 ui32MCUSB = (ui32TagSB >> 0) & 0x3;
+                               IMG_CHAR* pszReqOrig = "";
 
                                switch (ui32Req)
                                {
-                                       case 0x0: pszOrig = "ZLS"; break;
-                                       case 0x1: pszOrig = (ui32TagSB & 0x10)?"MCU":"PBE"; break;
-                                       case 0x2: pszOrig = "Host"; break;
-                                       case 0x3: pszOrig = "TLA"; break;
+                                       case 0x0: pszReqOrig = "FBC Request, originator ZLS";   break;
+                                       case 0x1: pszReqOrig = "FBC Request, originator PBE";   break;
+                                       case 0x2: pszReqOrig = "FBC Request, originator Host";  break;
+                                       case 0x3: pszReqOrig = "FBC Request, originator TLA";   break;
+                                       case 0x4: pszReqOrig = "FBDC Request, originator ZLS";  break;
+                                       case 0x5: pszReqOrig = "FBDC Request, originator MCU";  break;
+                                       case 0x6: pszReqOrig = "FBDC Request, originator Host"; break;
+                                       case 0x7: pszReqOrig = "FBDC Request, originator TLA";  break;
                                }
                                OSSNPrintf(pszScratchBuf, ui32ScratchBufSize,
-                                                       "%s Request, originator %s, MCU sideband 0x%X",
-                                                       pszReqId, pszOrig, ui32MCUSB);
+                                          "%s, MCU sideband 0x%X", pszReqOrig, ui32MCUSB);
                                pszTagSB = pszScratchBuf;
                        }
+#endif
                        break;
                }
        } /* switch(TagID) */
@@ -816,22 +848,31 @@ static IMG_VOID _RGXDecodeMMUReqTags(IMG_UINT32  ui32TagID,
 
                case RGXDBG_FBCDC:
                {
-                       IMG_UINT32 ui32Req = (ui32TagSB >> 2) & 0x3;
-                       IMG_UINT32 ui32MCUSB = ui32TagSB & 0x3;
-
-                       IMG_CHAR* pszReqId = (ui32TagSB & 0x10)?"FBDC":"FBC";
-                       IMG_CHAR* pszOrig = "";
+                       IMG_UINT32 ui32Req   = (ui32TagSB >> 0) & 0xf;
+                       IMG_UINT32 ui32MCUSB = (ui32TagSB >> 4) & 0x3;
+                       IMG_CHAR* pszReqOrig = "";
 
                        switch (ui32Req)
                        {
-                               case 0x0: pszOrig = "ZLS"; break;
-                               case 0x1: pszOrig = (ui32TagSB & 0x10)?"MCU":"PBE"; break;
-                               case 0x2: pszOrig = "Host"; break;
-                               case 0x3: pszOrig = "TLA"; break;
+                               case 0x0: pszReqOrig = "FBC Request, originator ZLS";  break;
+                               case 0x1: pszReqOrig = "FBC Request, originator PBE"; break;
+                               case 0x2: pszReqOrig = "FBC Request, originator Host"; break;
+                               case 0x3: pszReqOrig = "FBC Request, originator TLA"; break;
+                               case 0x4: pszReqOrig = "FBDC Request, originator ZLS"; break;
+                               case 0x5: pszReqOrig = "FBDC Request, originator MCU"; break;
+                               case 0x6: pszReqOrig = "FBDC Request, originator Host"; break;
+                               case 0x7: pszReqOrig = "FBDC Request, originator TLA"; break;
+                               case 0x8: pszReqOrig = "FBC Request, originator ZLS Requester Fence"; break;
+                               case 0x9: pszReqOrig = "FBC Request, originator PBE Requester Fence"; break;
+                               case 0xa: pszReqOrig = "FBC Request, originator Host Requester Fence"; break;
+                               case 0xb: pszReqOrig = "FBC Request, originator TLA Requester Fence"; break;
+                               case 0xc: pszReqOrig = "Reserved"; break;
+                               case 0xd: pszReqOrig = "Reserved"; break;
+                               case 0xe: pszReqOrig = "FBDC Request, originator FBCDC(Host) Memory Fence"; break;
+                               case 0xf: pszReqOrig = "FBDC Request, originator FBCDC(TLA) Memory Fence"; break;
                        }
                        OSSNPrintf(pszScratchBuf, ui32ScratchBufSize,
-                                               "%s Request, originator %s, MCU sideband 0x%X",
-                                               pszReqId, pszOrig, ui32MCUSB);
+                                  "%s, MCU sideband 0x%X", pszReqOrig, ui32MCUSB);
                        pszTagSB = pszScratchBuf;
                        break;
                }
@@ -1366,6 +1407,74 @@ static IMG_VOID _RGXDumpFWHWRInfo(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrintf,
        }       
 }
 
+#if !defined(NO_HARDWARE)
+
+/*!
+*******************************************************************************
+
+ @Function     _CheckForPendingPage
+
+ @Description
+
+ Check if the MMU indicates it is blocked on a pending page
+
+ @Input psDevInfo       - RGX device info
+
+ @Return   IMG_BOOL      - IMG_TRUE if there is a pending page
+
+******************************************************************************/
+static INLINE IMG_BOOL _CheckForPendingPage(PVRSRV_RGXDEV_INFO *psDevInfo)
+{
+       IMG_UINT32 ui32BIFMMUEntry;
+
+       ui32BIFMMUEntry = OSReadHWReg32(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_MMU_ENTRY);
+
+       if(ui32BIFMMUEntry & RGX_CR_BIF_MMU_ENTRY_PENDING_EN)
+       {
+               return IMG_TRUE;
+       }
+       else
+       {
+               return IMG_FALSE;
+       }
+}
+
+/*!
+*******************************************************************************
+
+ @Function     _GetPendingPageInfo
+
+ @Description
+
+ Get information about the pending page from the MMU status registers
+
+ @Input psDevInfo       - RGX device info
+ @Output psDevVAddr      - The device virtual address of the pending MMU address translation
+ @Output pui32CatBase    - The page catalog base
+ @Output pui32DataType   - The MMU entry data type
+
+ @Return   void
+
+******************************************************************************/
+static void _GetPendingPageInfo(PVRSRV_RGXDEV_INFO *psDevInfo, IMG_DEV_VIRTADDR *psDevVAddr,
+                                                                       IMG_UINT32 *pui32CatBase,
+                                                                       IMG_UINT32 *pui32DataType)
+{
+       IMG_UINT64 ui64BIFMMUEntryStatus;
+
+       ui64BIFMMUEntryStatus = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_MMU_ENTRY_STATUS);
+
+       psDevVAddr->uiAddr = (ui64BIFMMUEntryStatus & ~RGX_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_CLRMSK);
+
+       *pui32CatBase = (ui64BIFMMUEntryStatus & ~RGX_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_CLRMSK) >>
+                                                               RGX_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_SHIFT;
+
+       *pui32DataType = (ui64BIFMMUEntryStatus & ~RGX_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_CLRMSK) >>
+                                                               RGX_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_SHIFT;
+}
+
+#endif
+
 /*!
 *******************************************************************************
 
@@ -1433,6 +1542,37 @@ static IMG_VOID _RGXDumpRGXDebugSummary(DUMPDEBUG_PRINTF_FUNC *pfnDumpDebugPrint
 #endif
 #endif
 #endif
+
+#if !defined(NO_HARDWARE)
+               if(_CheckForPendingPage(psDevInfo))
+               {
+                       IMG_UINT32 ui32CatBase;
+                       IMG_UINT32 ui32DataType;
+                       IMG_DEV_VIRTADDR sDevVAddr;
+
+                       PVR_DUMPDEBUG_LOG(("MMU Pending page: Yes"));
+
+                       _GetPendingPageInfo(psDevInfo, &sDevVAddr, &ui32CatBase, &ui32DataType);
+
+                       if(ui32CatBase >= 8)
+                       {
+                               PVR_DUMPDEBUG_LOG(("Cannot check address on PM cat base %u", ui32CatBase));
+                       }
+                       else
+                       {
+                               IMG_DEV_PHYADDR sPCDevPAddr;
+
+                               sPCDevPAddr.uiAddr = OSReadHWReg64(psDevInfo->pvRegsBaseKM, RGX_CR_BIF_CAT_BASEN(ui32CatBase));
+
+                               PVR_DUMPDEBUG_LOG(("Checking device virtual address " IMG_DEV_VIRTADDR_FMTSPEC
+                                                       " on cat base %u. PC Addr = 0x%llX",
+                                                               (unsigned long long) sDevVAddr.uiAddr,
+                                                               ui32CatBase,
+                                                               (unsigned long long) sPCDevPAddr.uiAddr));
+                               RGXCheckFaultAddress(psDevInfo, &sDevVAddr, &sPCDevPAddr);
+                       }
+               }
+#endif /* NO_HARDWARE */
        }
 
        /* Firmware state */
index d8a3f2c8c4f747b52c12a3cac93c0face6b2b13b..5a3930c9fad60d07bb98685daa01533a22d68fc5 100644 (file)
@@ -877,7 +877,7 @@ PVRSRV_ERROR PVRSRVRGXCtrlHWPerfCountersKM(
 static POS_LOCK hFTraceLock;
 static IMG_VOID RGXHWPerfFTraceCmdCompleteNotify(PVRSRV_CMDCOMP_HANDLE);
 
-static IMG_VOID RGXHWPerfFTraceGPUEnable(void)
+static PVRSRV_ERROR RGXHWPerfFTraceGPUEnable(void)
 {
        PVRSRV_ERROR eError = PVRSRV_OK;
 
@@ -923,7 +923,7 @@ static IMG_VOID RGXHWPerfFTraceGPUEnable(void)
        gpsRgxDevInfo->bFTraceGPUEventsEnabled = IMG_TRUE;
 
 err_out:
-       PVR_DPF_RETURN;
+       PVR_DPF_RETURN_RC(eError);
 
 err_close_stream:
        TLClientCloseStream(gpsRgxDevInfo->hGPUTraceTLConnection,
@@ -933,9 +933,9 @@ err_disconnect:
        goto err_out;
 }
 
-static IMG_VOID RGXHWPerfFTraceGPUDisable(IMG_BOOL bDeInit)
+static PVRSRV_ERROR RGXHWPerfFTraceGPUDisable(IMG_BOOL bDeInit)
 {
-       PVRSRV_ERROR eError;
+       PVRSRV_ERROR eError = PVRSRV_OK;
 
        PVR_DPF_ENTERED;
 
@@ -978,12 +978,13 @@ static IMG_VOID RGXHWPerfFTraceGPUDisable(IMG_BOOL bDeInit)
 
        OSLockRelease(hFTraceLock);
 
-       PVR_DPF_RETURN;
+       PVR_DPF_RETURN_RC(eError);
 }
 
-IMG_VOID RGXHWPerfFTraceGPUEventsEnabledSet(IMG_BOOL bNewValue)
+PVRSRV_ERROR RGXHWPerfFTraceGPUEventsEnabledSet(IMG_BOOL bNewValue)
 {
        IMG_BOOL bOldValue;
+       PVRSRV_ERROR eError = PVRSRV_OK;
 
        PVR_DPF_ENTERED;
 
@@ -992,7 +993,8 @@ IMG_VOID RGXHWPerfFTraceGPUEventsEnabledSet(IMG_BOOL bNewValue)
                /* RGXHWPerfFTraceGPUInit hasn't been called yet -- it's too early
                 * to enable tracing.
                 */
-               PVR_DPF_RETURN;
+               eError = PVRSRV_ERROR_NO_DEVICEDATA_FOUND;
+               PVR_DPF_RETURN_RC(eError);
        }
 
        bOldValue = gpsRgxDevInfo->bFTraceGPUEventsEnabled;
@@ -1001,25 +1003,29 @@ IMG_VOID RGXHWPerfFTraceGPUEventsEnabledSet(IMG_BOOL bNewValue)
        {
                if (bNewValue)
                {
-                       RGXHWPerfFTraceGPUEnable();
+                       eError = RGXHWPerfFTraceGPUEnable();
                }
                else
                {
-                       RGXHWPerfFTraceGPUDisable(IMG_FALSE);
+                       eError = RGXHWPerfFTraceGPUDisable(IMG_FALSE);
                }
        }
 
-       PVR_DPF_RETURN;
+       PVR_DPF_RETURN_RC(eError);
 }
 
-IMG_VOID PVRGpuTraceEnabledSet(IMG_BOOL bNewValue)
+PVRSRV_ERROR PVRGpuTraceEnabledSet(IMG_BOOL bNewValue)
 {
+       PVRSRV_ERROR eError = PVRSRV_OK;
+
        /* Lock down because we need to protect
         * RGXHWPerfFTraceGPUDisable()/RGXHWPerfFTraceGPUEnable()
         */
        OSAcquireBridgeLock();
-       RGXHWPerfFTraceGPUEventsEnabledSet(bNewValue);
+       eError = RGXHWPerfFTraceGPUEventsEnabledSet(bNewValue);
        OSReleaseBridgeLock();
+
+       return eError;
 }
 
 IMG_BOOL RGXHWPerfFTraceGPUEventsEnabled(IMG_VOID)
index 1e5bd03ab21660230624ccb0a70a5ec9a2ff9e29..9e65d954a04ce9c1f56ad381433b9737483e888d 100644 (file)
@@ -103,7 +103,7 @@ IMG_VOID RGXHWPerfFTraceGPUEnqueueEvent(PVRSRV_RGXDEV_INFO *psDevInfo,
                IMG_UINT32 ui32ExternalJobRef, IMG_UINT32 ui32InternalJobRef,
                const IMG_CHAR* pszJobType);
 
-IMG_VOID RGXHWPerfFTraceGPUEventsEnabledSet(IMG_BOOL bNewValue);
+PVRSRV_ERROR RGXHWPerfFTraceGPUEventsEnabledSet(IMG_BOOL bNewValue);
 IMG_BOOL RGXHWPerfFTraceGPUEventsEnabled(IMG_VOID);
 
 IMG_VOID RGXHWPerfFTraceGPUThread(IMG_PVOID pvData);
index ad16d58bd7c6deccbbf62d3a2a71b51c6bd3b769..b9caeb92a285cfb3e21168679cdff2ad071b4cdd 100644 (file)
@@ -191,6 +191,13 @@ int MMapPMR(struct file *pFile, struct vm_area_struct *ps_vma)
 #if defined(PVR_MMAP_USE_VM_INSERT)
        IMG_BOOL bMixedMap = IMG_FALSE;
 #endif
+
+       if(psConnection == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "Invalid connection data"));
+               goto em0;
+       }
+
        /*
         * The pmr lock used here to protect both handle related operations and PMR
         * operations.
@@ -461,7 +468,7 @@ int MMapPMR(struct file *pFile, struct vm_area_struct *ps_vma)
     PVR_ASSERT(eError != PVRSRV_OK);
     PVR_DPF((PVR_DBG_ERROR, "unable to translate error %d", eError));
        mutex_unlock(&g_sMMapMutex);
-
+ em0:
     return -ENOENT; // -EAGAIN // or what?
 }
 
index 3e1d33e4ed8e28d261abba637621b8c2e46c090b..c190ce5c17cb9db8f78c5183c359935122c026c7 100755 (executable)
@@ -810,7 +810,7 @@ CONNECTION_DATA *LinuxConnectionFromFile(struct file *pFile)
 {
        PVRSRV_FILE_PRIVATE_DATA *psPrivateData = PRIVATE_DATA(pFile);
 
-       return psPrivateData->pvConnectionData;
+       return (psPrivateData == IMG_NULL) ? IMG_NULL : psPrivateData->pvConnectionData;
 }
 
 struct file *LinuxFileFromEnvConnection(ENV_CONNECTION_DATA *psEnvConnection)
index 66455008cd9e91b3ac8da6bfdaa15c72589c0d15..05265d4048afd45ce08315e6d1553be639f559d1 100644 (file)
@@ -90,6 +90,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #if defined(SUPPORT_SYSTEM_INTERRUPT_HANDLING)
 #include "syscommon.h"
 #endif
+#include "physmem_osmem_linux.h"
 
 #if defined(EMULATOR) || defined(VIRTUAL_PLATFORM)
 #define EVENT_OBJECT_TIMEOUT_MS                (2000)
@@ -290,7 +291,11 @@ PVRSRV_ERROR OSMMUPxMap(PVRSRV_DEVICE_NODE *psDevNode, Px_HANDLE *psMemHandle,
                /* vmalloc and friends expect a guard page so we need to take that into account */
                tmp_area.addr = (void *)uiCPUVAddr;
                tmp_area.size =  2 * PAGE_SIZE;
-               ret = map_vm_area(&tmp_area, prot, &ppsPage);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,17,0))
+               ret = map_vm_area(&tmp_area, prot, ppsPage);
+#else
+               ret = map_vm_area(&tmp_area, prot, & ppsPage);
+#endif
                if (ret) {
                        gen_pool_free(pvrsrv_pool_writecombine, uiCPUVAddr, PAGE_SIZE);
                        PVR_DPF((PVR_DBG_ERROR,
@@ -486,6 +491,8 @@ PVRSRV_ERROR OSInitEnvData(void)
        }
 #endif /* defined(CONFIG_GENERIC_ALLOCATOR) && defined(CONFIG_X86) && (LINUX_VERSION_CODE > KERNEL_VERSION(3,0,0)) */
 
+       LinuxInitPagePool();
+
        return PVRSRV_OK;
 }
 
@@ -511,6 +518,8 @@ void OSDeInitEnvData(void)
        psEnvData->pvBridgeData = IMG_NULL;
 
        OSFreeMem(psEnvData);
+
+       LinuxDeinitPagePool();
 }
 
 ENV_DATA *OSGetEnvData(void)
@@ -1991,6 +2000,12 @@ struct task_struct *OSGetBridgeLockOwner(void)
                                root.
 @Input          pfnGetElement  Pointer to function that can be used to obtain the
                                value of the statistic.
+@Input          pfnIncMemRefCt Pointer to function that can be used to take a
+                               reference on the memory backing the statistic
+                                                          entry.
+@Input          pfnDecMemRefCt Pointer to function that can be used to drop a
+                               reference on the memory backing the statistic
+                                                          entry.
 @Input          pvData         OS specific reference that can be used by
                                pfnGetElement.
 @Return         Pointer void reference to the entry created, which can be
@@ -1998,9 +2013,11 @@ struct task_struct *OSGetBridgeLockOwner(void)
 */ /**************************************************************************/
 IMG_PVOID OSCreateStatisticEntry(IMG_CHAR* pszName, IMG_PVOID pvFolder,
                                  OS_GET_STATS_ELEMENT_FUNC* pfnGetElement,
+                                                                OS_INC_STATS_MEM_REFCOUNT_FUNC* pfnIncMemRefCt,
+                                                                OS_DEC_STATS_MEM_REFCOUNT_FUNC* pfnDecMemRefCt,
                                  IMG_PVOID pvData)
 {
-       return PVRDebugFSCreateStatisticEntry(pszName, pvFolder, pfnGetElement, pvData);
+       return PVRDebugFSCreateStatisticEntry(pszName, (PVR_DEBUGFS_DIR_DATA *)pvFolder, pfnGetElement, pfnIncMemRefCt, pfnDecMemRefCt, pvData);
 } /* OSCreateStatisticEntry */
 
 
@@ -2012,7 +2029,7 @@ IMG_PVOID OSCreateStatisticEntry(IMG_CHAR* pszName, IMG_PVOID pvFolder,
 */ /**************************************************************************/
 void OSRemoveStatisticEntry(IMG_PVOID pvEntry)
 {
-       PVRDebugFSRemoveStatisticEntry(pvEntry);
+       PVRDebugFSRemoveStatisticEntry((PVR_DEBUGFS_DRIVER_STAT *)pvEntry);
 } /* OSRemoveStatisticEntry */
 
 
@@ -2027,12 +2044,11 @@ void OSRemoveStatisticEntry(IMG_PVOID pvEntry)
 */ /**************************************************************************/
 IMG_PVOID OSCreateStatisticFolder(IMG_CHAR *pszName, IMG_PVOID pvFolder)
 {
-       struct dentry *psDir;
+       PVR_DEBUGFS_DIR_DATA *psNewStatFolder = IMG_NULL;
        int iResult;
 
-       iResult = PVRDebugFSCreateEntryDir(pszName, pvFolder, &psDir);
-
-       return (iResult == 0) ? psDir : IMG_NULL;
+       iResult = PVRDebugFSCreateEntryDir(pszName, (PVR_DEBUGFS_DIR_DATA *)pvFolder, &psNewStatFolder);
+       return (iResult == 0) ? (void *)psNewStatFolder : IMG_NULL;
 } /* OSCreateStatisticFolder */
 
 
@@ -2044,5 +2060,5 @@ IMG_PVOID OSCreateStatisticFolder(IMG_CHAR *pszName, IMG_PVOID pvFolder)
 */ /**************************************************************************/
 void OSRemoveStatisticFolder(IMG_PVOID pvFolder)
 {
-       PVRDebugFSRemoveEntryDir((struct dentry *)pvFolder);
+       PVRDebugFSRemoveEntryDir((PVR_DEBUGFS_DIR_DATA *)pvFolder);
 } /* OSRemoveStatisticFolder */
index 1488553e6a0df86db085735705bf9ef1d9426103..f21921597d8eb1b491313e9e41ae1aa9f084e257 100644 (file)
@@ -132,9 +132,6 @@ PVRSRV_ERROR OSSecureExport(CONNECTION_DATA *psConnection,
                goto e0;
        }
 
-       /* Bind our struct file with it's fd number */
-       fd_install(secure_fd, secure_file);
-
        /* Return the new services connection our secure data created */
 #if defined(SUPPORT_DRM)
        psSecureConnection = LinuxConnectionFromFile(PVR_DRM_FILE_FROM_FILE(secure_file));
@@ -142,6 +139,16 @@ PVRSRV_ERROR OSSecureExport(CONNECTION_DATA *psConnection,
        psSecureConnection = LinuxConnectionFromFile(secure_file);
 #endif
 
+       if(psSecureConnection == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "Invalid connection data"));
+               eError = PVRSRV_ERROR_INVALID_PARAMS;
+               goto e0;
+       }
+
+       /* Bind our struct file with it's fd number */
+       fd_install(secure_fd, secure_file);
+
        /* Save the private data */
        PVR_ASSERT(psSecureConnection->hSecureData == IMG_NULL);
        psSecureConnection->hSecureData = pvData;
index 4299add0737f985b90a09a9bd5a249ad86cb2ea2..dd8e0a4d1543dae75c395d94ca19643fe375baa3 100755 (executable)
@@ -60,6 +60,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 /* ourselves */
 #include "physmem_osmem.h"
+#include "physmem_osmem_linux.h"
 
 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
 #include "process_stats.h"
@@ -137,8 +138,42 @@ struct _PMR_OSPAGEARRAY_DATA_ {
        */
     IMG_UINT32 ui32CPUCacheFlags;
        IMG_BOOL bUnsetMemoryType;
+
+    /*
+      structure used to hook in to the resman queue of additionally
+      deferred work, to be done without the bridge lock held
+    */
+    RESMAN_FREE_FN_AND_DATA sResManData;
 };
 
+/* clone a PMR_OSPAGEARRAY_DATA structure, including making a copy of
+ * the the list of physical pages it owns.
+ * returns a pointer to the newly allocated PMR_OSPAGEARRAY_DATA structure.
+ */
+static struct _PMR_OSPAGEARRAY_DATA_ *_CloneOSPageArrayData(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayDataIn)
+{
+       struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayDataOut;
+       size_t uiStructureSize;
+
+       uiStructureSize = sizeof(struct _PMR_OSPAGEARRAY_DATA_) +
+                                               sizeof(struct page *) * psPageArrayDataIn->uiNumPages;
+
+       psPageArrayDataOut = OSAllocMemstatMem(uiStructureSize);
+
+       if(psPageArrayDataOut == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "_CloneOSPageArrayData: Failed to clone PMR_OSPAGEARRAY_DATA"));
+               return IMG_NULL;
+       }
+
+       memcpy(psPageArrayDataOut, psPageArrayDataIn, uiStructureSize);
+
+       psPageArrayDataOut->pagearray = (void *) ((char *) psPageArrayDataOut) +
+                                               sizeof(struct _PMR_OSPAGEARRAY_DATA_);
+
+       return psPageArrayDataOut;
+}
+
 /***********************************
  * Page pooling for uncached pages *
  ***********************************/
@@ -161,7 +196,6 @@ typedef     struct
 /* Track what is live */
 static IMG_UINT32 g_ui32PagePoolEntryCount = 0;
 static IMG_UINT32 g_ui32PagePoolMaxEntries = PVR_LINUX_PYSMEM_MAX_POOL_PAGES;
-static IMG_UINT32 g_ui32LiveAllocs = 0;
 
 /* Global structures we use to manage the page pool */
 static struct kmem_cache *g_psLinuxPagePoolCache = IMG_NULL;
@@ -432,11 +466,10 @@ static void DisableOOMKiller(void)
        current->flags |= PF_DUMPCORE;
 }
 
-static void _InitPagePool(void)
+void LinuxInitPagePool(void)
 {
        IMG_UINT32 ui32Flags = 0;
 
-       _PagePoolLock();
 #if defined(DEBUG_LINUX_SLAB_ALLOCATIONS)
        ui32Flags |= SLAB_POISON|SLAB_RED_ZONE;
 #endif
@@ -449,14 +482,12 @@ static void _InitPagePool(void)
                register_shrinker(&g_sShrinker);
        }
 #endif
-       _PagePoolUnlock();
 }
 
-static void _DeinitPagePool(void)
+void LinuxDeinitPagePool(void)
 {
        LinuxPagePoolEntry *psPagePoolEntry, *psTempPoolEntry;
 
-       _PagePoolLock();
        /* Evict all the pages from the pool */
        list_for_each_entry_safe(psPagePoolEntry, psTempPoolEntry, &g_sPagePoolList, sPagePoolItem)
        {
@@ -512,7 +543,6 @@ static void _DeinitPagePool(void)
 #if defined(PHYSMEM_SUPPORTS_SHRINKER)
        unregister_shrinker(&g_sShrinker);
 #endif
-       _PagePoolUnlock();
 }
 
 static void EnableOOMKiller(void)
@@ -669,49 +699,6 @@ _AllocOSPage(IMG_UINT32 ui32CPUCacheFlags,
         DisableOOMKiller();
         psPage = alloc_pages(gfp_flags, uiOrder);
         EnableOOMKiller();
-
-#if defined (CONFIG_ARM) || defined(CONFIG_ARM64) || defined (CONFIG_METAG)
-               /*
-               On ARM kernels we can be given pages which still remain in the cache.
-               In order to make sure that the data we write through our mappings
-               doesn't get over written by later cache evictions we invalidate the
-               pages that get given to us.
-
-               Note:
-               This still seems to be true if we request cold pages, it's just less
-               likely to be in the cache.
-               */
-               if (psPage != IMG_NULL)
-               {
-                       pvPageVAddr = kmap(psPage);
-
-                       if (ui32CPUCacheFlags != PVRSRV_MEMALLOCFLAG_CPU_CACHED)
-                       {
-                               IMG_CPU_PHYADDR sCPUPhysAddrStart, sCPUPhysAddrEnd;
-
-                               sCPUPhysAddrStart.uiAddr = page_to_phys(psPage);
-                               sCPUPhysAddrEnd.uiAddr = sCPUPhysAddrStart.uiAddr + PAGE_SIZE;
-
-                               /* If we're zeroing, we need to make sure the cleared memory is pushed out
-                                       of the cache before the cache lines are invalidated */
-                               if (bFlush)
-                               {
-                                       OSFlushCPUCacheRangeKM(pvPageVAddr,
-                                                                                               pvPageVAddr + PAGE_SIZE,
-                                                                                               sCPUPhysAddrStart,
-                                                                                               sCPUPhysAddrEnd);
-                               }
-                               else
-                               {
-                                       OSInvalidateCPUCacheRangeKM(pvPageVAddr,
-                                                                                               pvPageVAddr + PAGE_SIZE,
-                                                                                               sCPUPhysAddrStart,
-                                                                                               sCPUPhysAddrEnd);
-                               }
-                       }
-                       kunmap(psPage);
-               }
-#endif
        }
        else
        {
@@ -831,11 +818,11 @@ _AllocOSPages(struct _PMR_OSPAGEARRAY_DATA_ **ppsPageArrayDataPtr)
 
     unsigned int gfp_flags;
 
-#if defined (CONFIG_X86)
     /* On x86 we might have to change the page cache attributes.
      * We do this by storing references to all the changed pages that are not
      * from the page pool and then set the attribute of all the pages at once.
      * This saves us calling set_memory_XX() and therefore a cache flush every time
+     * On ARM we have to just invalidate pages that have different cache attributes..
      */
     struct page **apsUnsetPages = OSAllocMem(sizeof(struct page*) * psPageArrayData->uiNumPages);
     IMG_UINT32 uiUnsetPagesIndex = 0;
@@ -847,26 +834,14 @@ _AllocOSPages(struct _PMR_OSPAGEARRAY_DATA_ **ppsPageArrayDataPtr)
        goto e_exit;
     }
 
-#endif
-
-
-
     PVR_ASSERT(!psPageArrayData->bHasOSPages);
 
-       /* Try and create the page pool if required */
-       if ((g_ui32PagePoolMaxEntries > 0) && (g_psLinuxPagePoolCache == NULL))
-       {
-               _InitPagePool();
-       }
-
     uiOrder = psPageArrayData->uiLog2PageSize - PAGE_SHIFT;
     ui32CPUCacheFlags = psPageArrayData->ui32CPUCacheFlags;
 
     gfp_flags = GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC;
 
-#if defined(CONFIG_X86)
-    gfp_flags |= __GFP_DMA32;
-#else
+#if !defined(CONFIG_X86)
     gfp_flags |= __GFP_HIGHMEM;
 #endif
 
@@ -914,13 +889,11 @@ _AllocOSPages(struct _PMR_OSPAGEARRAY_DATA_ **ppsPageArrayDataPtr)
                                                          &ppsPageArray[uiPageIndex],
                                                          &bPageFromPool);
 
-#if defined(CONFIG_X86)
                if (!bPageFromPool)
                {
                        apsUnsetPages[uiUnsetPagesIndex] = ppsPageArray[uiPageIndex];
                        uiUnsetPagesIndex++;
                }
-#endif
 
         if (eError != PVRSRV_OK)
         {
@@ -969,6 +942,58 @@ _AllocOSPages(struct _PMR_OSPAGEARRAY_DATA_ **ppsPageArrayDataPtr)
 #endif
 #endif
     }
+#if defined (CONFIG_ARM) || defined(CONFIG_ARM64) || defined (CONFIG_METAG)
+               /*
+               On ARM kernels we can be given pages which still remain in the cache.
+               In order to make sure that the data we write through our mappings
+               doesn't get over written by later cache evictions we invalidate the
+               pages that get given to us.
+
+               Note:
+               This still seems to be true if we request cold pages, it's just less
+               likely to be in the cache.
+               */
+               if (ui32CPUCacheFlags != PVRSRV_MEMALLOCFLAG_CPU_CACHED)
+               {
+                       if (uiUnsetPagesIndex < PVR_LINUX_ARM_PAGEALLOC_FLUSH_THRESHOLD)
+                       {
+                               int i;
+                               void* pvPageVAddr;
+                               for (i = 0; i < uiUnsetPagesIndex; i++)
+                               {
+
+                                       IMG_CPU_PHYADDR sCPUPhysAddrStart, sCPUPhysAddrEnd;
+                                       pvPageVAddr = kmap(apsUnsetPages[i]);
+
+                                       sCPUPhysAddrStart.uiAddr = page_to_phys(apsUnsetPages[i]);
+                                       sCPUPhysAddrEnd.uiAddr = sCPUPhysAddrStart.uiAddr + PAGE_SIZE;
+
+                                       /* If we're zeroing, we need to make sure the cleared memory is pushed out
+                                               of the cache before the cache lines are invalidated */
+                                       if (psPageArrayData->bZero)
+                                       {
+                                               OSFlushCPUCacheRangeKM(pvPageVAddr,
+                                                                      pvPageVAddr + PAGE_SIZE,
+                                                                      sCPUPhysAddrStart,
+                                                                      sCPUPhysAddrEnd);
+                                       }
+                                       else
+                                       {
+                                               OSInvalidateCPUCacheRangeKM(pvPageVAddr,
+                                                                           pvPageVAddr + PAGE_SIZE,
+                                                                           sCPUPhysAddrStart,
+                                                                           sCPUPhysAddrEnd);
+                                       }
+
+                                       kunmap(apsUnsetPages[i]);
+                               }
+                       }
+                       else
+                       {
+                               OSCPUOperation(PVRSRV_CACHE_OP_FLUSH);
+                       }
+               }
+#endif
 
 #if defined (CONFIG_X86)
        /*
@@ -1020,16 +1045,14 @@ _AllocOSPages(struct _PMR_OSPAGEARRAY_DATA_ **ppsPageArrayDataPtr)
                }
 
        }
-
-       OSFreeMem(apsUnsetPages);
 #endif
+       OSFreeMem(apsUnsetPages);
 
 
     /* OS Pages have been allocated */
     psPageArrayData->bHasOSPages = IMG_TRUE;
 
     PVR_DPF((PVR_DBG_MESSAGE, "physmem_osmem_linux.c: allocated OS memory for PMR @0x%p", psPageArrayData));
-    g_ui32LiveAllocs++;
 
     return PVRSRV_OK;
 
@@ -1038,10 +1061,8 @@ _AllocOSPages(struct _PMR_OSPAGEARRAY_DATA_ **ppsPageArrayDataPtr)
     */
 
 e_freed_pages:
-#if defined (CONFIG_X86)
        OSFreeMem(apsUnsetPages);
 e_exit:
-#endif
     PVR_ASSERT(eError != PVRSRV_OK);
     return eError;
 }
@@ -1056,8 +1077,44 @@ _FreeOSPagesArray(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
     return PVRSRV_OK;
 }
 
+#if defined(PVRSRV_ENABLE_PROCESS_STATS)
+/* _FreeOSPages_MemStats: Depends on the bridge lock already being held */
 static PVRSRV_ERROR
-_FreeOSPages(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
+_FreeOSPages_MemStats(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
+{
+    IMG_UINT32 uiNumPages;
+    struct page **ppsPageArray;
+#if defined(PVRSRV_ENABLE_MEMORY_STATS)
+    IMG_UINT32 uiPageIndex;
+#endif
+
+       PVR_ASSERT(psPageArrayData->bHasOSPages);
+
+    ppsPageArray = psPageArrayData->pagearray;
+
+    uiNumPages = psPageArrayData->uiNumPages;
+
+#if !defined(PVRSRV_ENABLE_MEMORY_STATS)
+       PVRSRVStatsDecrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES, uiNumPages * PAGE_SIZE);
+#else
+
+       for (uiPageIndex = 0;
+                uiPageIndex < uiNumPages;
+                uiPageIndex++)
+       {
+                       IMG_CPU_PHYADDR sCPUPhysAddr;
+                       sCPUPhysAddr.uiAddr = page_to_phys(ppsPageArray[uiPageIndex]);
+                       PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES, sCPUPhysAddr.uiAddr);
+       }
+#endif /* !defined(PVRSRV_ENABLE_MEMORY_STATS) */
+
+    return PVRSRV_OK;
+}
+#endif /* PVRSRV_ENABLE_PROCESS_STATS */
+
+/* _FreeOSPages_FreePages: Does not require the bridge lock */
+static PVRSRV_ERROR
+_FreeOSPages_FreePages(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
 {
     PVRSRV_ERROR eError;
     IMG_UINT32 uiNumPages;
@@ -1068,7 +1125,7 @@ _FreeOSPages(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
 
 #if defined (CONFIG_X86)
        IMG_UINT32 uiUnsetPagesIndex = 0;
-       struct page **apsUnsetPages = OSAllocMem(sizeof(struct page *) * psPageArrayData->uiNumPages);
+       struct page **apsUnsetPages = OSAllocMemstatMem(sizeof(struct page *) * psPageArrayData->uiNumPages);
 
        if (apsUnsetPages == NULL)
        {
@@ -1079,9 +1136,6 @@ _FreeOSPages(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
        }
 #endif
 
-       PVR_ASSERT(psPageArrayData->bHasOSPages);
-       g_ui32LiveAllocs--;
-
     ppsPageArray = psPageArrayData->pagearray;
 
     uiNumPages = psPageArrayData->uiNumPages;
@@ -1100,20 +1154,6 @@ _FreeOSPages(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
                                                 _FreePoisonSize);
                }
 
-#if defined(PVRSRV_ENABLE_PROCESS_STATS)
-#if !defined(PVRSRV_ENABLE_MEMORY_STATS)
-               /* Allocation is done a page at a time */
-               PVRSRVStatsDecrMemAllocStat(PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES, PAGE_SIZE);
-#else
-               {
-                       IMG_CPU_PHYADDR sCPUPhysAddr;
-                       sCPUPhysAddr.uiAddr = page_to_phys(ppsPageArray[uiPageIndex]);
-                       PVRSRVStatsRemoveMemAllocRecord(PVRSRV_MEM_ALLOC_TYPE_ALLOC_UMA_PAGES, sCPUPhysAddr.uiAddr);
-               }
-#endif
-#endif
-
-
                /* Only zero order pages can be managed in the pool */
                if (uiOrder == 0)
                {
@@ -1166,21 +1206,147 @@ _FreeOSPages(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData)
                }
        }
 
-       OSFreeMem(apsUnsetPages);
+       OSFreeMemstatMem(apsUnsetPages);
 #endif
 
+    psPageArrayData->bHasOSPages = IMG_FALSE;
+
     eError = PVRSRV_OK;
 
-    psPageArrayData->bHasOSPages = IMG_FALSE;
+#if defined(CONFIG_X86)
+e_exit:
+#endif
+    return eError;
+}
+
+static PVRSRV_ERROR
+_FreeOSPages_FreePagesAndFreeStructure(void *pvData)
+{
+       struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData = pvData;
+       PVRSRV_ERROR eError;
+
+       eError = _FreeOSPages_FreePages(psPageArrayData);
 
-       /* Destroy the page pool if required */
-       if ((g_ui32PagePoolMaxEntries > 0) && (g_psLinuxPagePoolCache != NULL) && (g_ui32LiveAllocs == 0))
+       if(eError != PVRSRV_OK)
        {
-               _DeinitPagePool();
+               PVR_DPF((PVR_DBG_ERROR, "_FreeOSPages_FreePagesAndFreeStructure: _FreeOSPages_FreePages failed"));
        }
-#if defined(CONFIG_X86)
-e_exit:
+       else
+       {
+               eError = _FreeOSPagesArray(psPageArrayData);
+       }
+
+       return eError;
+}
+
+static PVRSRV_ERROR
+_FreeOSPages(struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayData, IMG_BOOL bFreePageArray)
+{
+       PVRSRV_ERROR eError = PVRSRV_OK;
+
+       /* if this is a deferred callback then have resman do the work in two parts,
+        * with the second part without the bridge lock held
+        */
+        if(PVRSRVResManInDeferredCleanup())
+        {
+               /* if the page array data structure (struct _PMR_OSPAGEARRAY_DATA_) is
+                * being freed then we can go ahead and put the structure on the
+                * deferred free list.
+                * otherwise, the _PMR_OSPAGEARRAY_DATA_ structure may be re-used so its
+                * contents cannot be relied upon to be stable when the bridge lock is not held.
+                * for this reason we fork/clone the _PMR_OSPAGEARRAY_DATA_ structure and move
+                * ownership of the pages onto the new structure. the existing _PMR_OSPAGEARRAY_DATA_
+                * structure immediately has no pages belonging to it.
+                */
+               if(bFreePageArray)
+               {
+#if defined(PVRSRV_ENABLE_PROCESS_STATS)
+                       eError = _FreeOSPages_MemStats(psPageArrayData);
+
+                       if(eError != PVRSRV_OK)
+                       {
+                               PVR_DPF((PVR_DBG_ERROR, "_FreeOSPages_MemStats failed"));
+                       }
 #endif
+
+                       /* set up the deferred work */
+                       psPageArrayData->sResManData.pfnFree = _FreeOSPages_FreePagesAndFreeStructure;
+                       psPageArrayData->sResManData.pvParam = psPageArrayData;
+
+                       PVRSRVResManAddNoBridgeLockCallback(&psPageArrayData->sResManData);
+               }
+               else
+               {
+                       struct _PMR_OSPAGEARRAY_DATA_ *psPageArrayDataClone;
+
+                       /* we are only expected to free the physical backing, not the PMR OS page array data structure.
+                        * because the PMR OS page array may be re-mapped, the existing struct _PMR_OSPAGEARRAY_DATA_
+                        * cannot be passed to the async/deferred free function (the re-mapping may occur before
+                        * the free). So at this point we detach the physical page list from the
+                        * struct _PMR_OSPAGEARRAY_DATA_ and leave the struct _PMR_OSPAGEARRAY_DATA_ intact,
+                        * only modifying its 'bHasOSPages' boolean to reflect it no longer owns
+                        * any OS allocated pages
+                        */
+
+                       psPageArrayDataClone = _CloneOSPageArrayData(psPageArrayData);
+
+                       if(psPageArrayDataClone == NULL)
+                       {
+                               /* failed to clone the structure so we cannot defer this work. do it immediately */
+                               goto free_immediately;
+                       }
+
+                       /* psPageArrayDataClone takes ownership of the pages, so mark
+                        * psPageArrayData as not having any pages
+                        */
+                       psPageArrayData->bHasOSPages = IMG_FALSE;
+
+#if defined(PVRSRV_ENABLE_PROCESS_STATS)
+                       eError = _FreeOSPages_MemStats(psPageArrayDataClone);
+
+                       if(eError != PVRSRV_OK)
+                       {
+                               PVR_DPF((PVR_DBG_ERROR, "_FreeOSPages_MemStats failed"));
+                       }
+#endif
+
+                       /* set up the deferred work */
+                       psPageArrayDataClone->sResManData.pfnFree = _FreeOSPages_FreePagesAndFreeStructure;
+                       psPageArrayDataClone->sResManData.pvParam = psPageArrayDataClone;
+
+                       PVRSRVResManAddNoBridgeLockCallback(&psPageArrayDataClone->sResManData);
+               }
+
+               return PVRSRV_OK;
+        }
+
+free_immediately:
+
+       /* immediately free the pages and, if specified, the _PMR_OSPAGEARRAY_DATA_ structure */
+
+#if defined(PVRSRV_ENABLE_PROCESS_STATS)
+       eError = _FreeOSPages_MemStats(psPageArrayData);
+
+       if(eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "_FreeOSPages_MemStats failed"));
+       }
+#endif
+
+       eError = _FreeOSPages_FreePages(psPageArrayData);
+
+       if(eError != PVRSRV_OK)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "_FreeOSPages_FreePages failed"));
+               goto err_out;
+       }
+
+       if(bFreePageArray)
+       {
+               eError = _FreeOSPagesArray(psPageArrayData);
+       }
+
+err_out:
     return eError;
 }
 
@@ -1212,12 +1378,13 @@ PMRFinalizeOSMem(PMR_IMPL_PRIVDATA pvPriv
     /*  We can't free pages until now. */
     if (psOSPageArrayData->bHasOSPages)
     {
-               eError = _FreeOSPages(psOSPageArrayData);
+               eError = _FreeOSPages(psOSPageArrayData, IMG_TRUE);
                PVR_ASSERT (eError == PVRSRV_OK); /* can we do better? */
     }
-
-    eError = _FreeOSPagesArray(psOSPageArrayData);
-    PVR_ASSERT (eError == PVRSRV_OK); /* can we do better? */
+    else
+    {
+       _FreeOSPagesArray(psOSPageArrayData);
+    }
 
     return PVRSRV_OK;
 }
@@ -1277,7 +1444,7 @@ PMRUnlockSysPhysAddressesOSMem(PMR_IMPL_PRIVDATA pvPriv
     if (psOSPageArrayData->bOnDemand)
     {
                /* Free Memory for deferred allocation */
-       eError = _FreeOSPages(psOSPageArrayData);
+       eError = _FreeOSPages(psOSPageArrayData, IMG_FALSE);
        if (eError != PVRSRV_OK)
        {
                return eError;
@@ -1603,7 +1770,7 @@ _NewOSAllocPagesPMR(PVRSRV_DEVICE_NODE *psDevNode,
 errorOnCreate:
        if (!bOnDemand)
        {
-               eError2 = _FreeOSPages(psPrivData);
+               eError2 = _FreeOSPages(psPrivData, IMG_FALSE);
                PVR_ASSERT(eError2 == PVRSRV_OK);
        }
 
diff --git a/drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.h b/drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.h
new file mode 100644 (file)
index 0000000..f247875
--- /dev/null
@@ -0,0 +1,49 @@
+/*************************************************************************/ /*!
+@File
+@Title          Linux OS physmem implementation
+@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
+@License        Dual MIT/GPLv2
+
+The contents of this file are subject to the MIT license as set out below.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Alternatively, the contents of this file may be used under the terms of
+the GNU General Public License Version 2 ("GPL") in which case the provisions
+of GPL are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms of
+GPL, and not to allow others to use your version of this file under the terms
+of the MIT license, indicate your decision by deleting the provisions above
+and replace them with the notice and other provisions required by GPL as set
+out in the file called "GPL-COPYING" included in this distribution. If you do
+not delete the provisions above, a recipient may use your version of this file
+under the terms of either the MIT license or GPL.
+
+This License is also included in this distribution in the file called
+"MIT-COPYING".
+
+EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
+PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/ /**************************************************************************/
+
+#if !defined(__PHYSMEM_OSMEM_LINUX_H__)
+#define __PHYSMEM_OSMEM_LINUX_H__
+
+void LinuxInitPagePool(void);
+void LinuxDeinitPagePool(void);
+
+#endif /* __PHYSMEM_OSMEM_LINUX_H__ */
index 7ba442cd37628b88b757c88e3137b5aef31a7f80..108c6d859e4ab83f67140550e819407a5ce97919 100644 (file)
@@ -87,7 +87,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #endif
 
 #if defined(DEBUG_BRIDGE_KM)
-static struct dentry *gpsPVRDebugFSBridgeStatsEntry = NULL;
+static PVR_DEBUGFS_ENTRY_DATA *gpsPVRDebugFSBridgeStatsEntry = NULL;
 static struct seq_operations gsBridgeStatsReadOps;
 #endif
 
@@ -157,7 +157,7 @@ LinuxBridgeInit(void)
                                        &gsBridgeStatsReadOps,
                                        NULL,
                                        &g_BridgeDispatchTable[0],
-                                       &gpsPVRDebugFSBridgeStatsEntry);
+                    &gpsPVRDebugFSBridgeStatsEntry);
        if (iResult != 0)
        {
                return PVRSRV_ERROR_OUT_OF_MEMORY;
@@ -349,8 +349,8 @@ void
 LinuxBridgeDeInit(void)
 {
 #if defined(DEBUG_BRIDGE_KM)
-       PVRDebugFSRemoveEntry(gpsPVRDebugFSBridgeStatsEntry);
-       gpsPVRDebugFSBridgeStatsEntry = NULL;
+    PVRDebugFSRemoveEntry(gpsPVRDebugFSBridgeStatsEntry);
+    gpsPVRDebugFSBridgeStatsEntry = NULL;
 #endif
 }
 
@@ -459,11 +459,19 @@ PVRSRV_BridgeDispatchKM(struct file *pFile, unsigned int unref__ ioctlCmd, unsig
        PVRSRV_BRIDGE_PACKAGE sBridgePackageKM;
 #endif
        PVRSRV_BRIDGE_PACKAGE *psBridgePackageKM;
-       CONNECTION_DATA *psConnection = LinuxConnectionFromFile(pFile);
+       CONNECTION_DATA *psConnection;
        IMG_INT err = -EFAULT;
 
        OSAcquireBridgeLock();
 
+       psConnection = LinuxConnectionFromFile(pFile);
+       if(psConnection == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "%s: Connection is closed", __FUNCTION__));
+               OSReleaseBridgeLock();
+               return err;
+       }
+
 #if defined(SUPPORT_DRM)
        PVR_UNREFERENCED_PARAMETER(dev);
 
@@ -542,17 +550,28 @@ PVRSRV_BridgeCompatDispatchKM(struct file *pFile,
        PVRSRV_BRIDGE_PACKAGE params_for_64;
        struct bridge_package_from_32 params;
        struct bridge_package_from_32 * const params_addr = &params;
-#if !defined(SUPPORT_DRM)
-       CONNECTION_DATA *psConnection = LinuxConnectionFromFile(pFile);
-#else
-       struct drm_file *file_priv = pFile->private_data;
-       CONNECTION_DATA *psConnection = LinuxConnectionFromFile(file_priv);
+#if defined(SUPPORT_DRM)
+       struct drm_file *file_priv;
 #endif
+       CONNECTION_DATA *psConnection;
+
        // make sure there is no padding inserted by compiler
        PVR_ASSERT(sizeof(struct bridge_package_from_32) == 6 * sizeof(IMG_UINT32));
 
        OSAcquireBridgeLock();
 
+#if !defined(SUPPORT_DRM)
+       psConnection = LinuxConnectionFromFile(pFile);
+#else
+       file_priv = pFile->private_data;
+       psConnection = LinuxConnectionFromFile(file_priv);
+#endif
+       if(psConnection == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR, "%s: Connection is closed", __FUNCTION__));
+               goto unlock_and_return;
+       }
+
        if(!OSAccessOK(PVR_VERIFY_READ, (void *) arg,
                                   sizeof(struct bridge_package_from_32)))
        {
index ec647497faf1c14f6ce7fd21125663099b4e2b7b..965a85144dbd444d6fe96d95941ef79825bbb4c7 100755 (executable)
@@ -1310,17 +1310,18 @@ static IMG_INT DebugLevelSet(const char __user *pcBuffer,
 }
 #endif /* defined(DEBUG) */
 
-static struct dentry *gpsVersionDebugFSEntry;
-static struct dentry *gpsNodesDebugFSEntry;
-static struct dentry *gpsStatusDebugFSEntry;
-static struct dentry *gpsDumpDebugDebugFSEntry;
+
+static PVR_DEBUGFS_ENTRY_DATA *gpsVersionDebugFSEntry;
+static PVR_DEBUGFS_ENTRY_DATA *gpsNodesDebugFSEntry;
+static PVR_DEBUGFS_ENTRY_DATA *gpsStatusDebugFSEntry;
+static PVR_DEBUGFS_ENTRY_DATA *gpsDumpDebugDebugFSEntry;
 
 #if defined(PVRSRV_ENABLE_FW_TRACE_DEBUGFS)
-static struct dentry *gpsFWTraceDebugFSEntry;
+static PVR_DEBUGFS_ENTRY_DATA *gpsFWTraceDebugFSEntry;
 #endif
 
 #if defined(DEBUG)
-static struct dentry *gpsDebugLevelDebugFSEntry;
+static PVR_DEBUGFS_ENTRY_DATA *gpsDebugLevelDebugFSEntry;
 #endif
 
 int PVRDebugCreateDebugFSEntries(void)
@@ -1337,6 +1338,7 @@ int PVRDebugCreateDebugFSEntries(void)
                                        NULL,
                                        psPVRSRVData,
                                        &gpsVersionDebugFSEntry);
+
        if (iResult != 0)
        {
                return iResult;
@@ -1475,5 +1477,6 @@ void PVRDebugRemoveDebugFSEntries(void)
                PVRDebugFSRemoveEntry(gpsVersionDebugFSEntry);
                gpsVersionDebugFSEntry = NULL;
        }
+
 }
 
index 044622cda23d5f7eb331cdc5be8a02cebe7c320e..b37f4ad3eca067436c500e60095fc26eda716b3c 100644 (file)
@@ -50,6 +50,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 static struct dentry *gpsPVRDebugFSEntryDir = NULL;
 
+/* Lock used when adjusting refCounts and deleting entries */
+static struct mutex gDebugFSLock;
 
 /*************************************************************************/ /*!
  Statistic entry read functions
@@ -57,47 +59,107 @@ static struct dentry *gpsPVRDebugFSEntryDir = NULL;
 
 typedef struct _PVR_DEBUGFS_DRIVER_STAT_
 {
-       struct dentry                   *psEntry;
        void                            *pvData;
        PVRSRV_GET_NEXT_STAT_FUNC       *pfnGetNextStat;
+       PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC       *pfnIncStatMemRefCount;
+       PVRSRV_DEC_STAT_MEM_REFCOUNT_FUNC       *pfnDecStatMemRefCount;
+       IMG_UINT32                      ui32RefCount;
        IMG_INT32                       i32StatValue;
        IMG_CHAR                        *pszStatFormat;
+       PVR_DEBUGFS_ENTRY_DATA  *pvDebugFSEntry;
 } PVR_DEBUGFS_DRIVER_STAT;
-
+typedef struct _PVR_DEBUGFS_DIR_DATA_
+{
+       struct dentry *psDir;
+       PVR_DEBUGFS_DIR_DATA *psParentDir;
+       IMG_UINT32      ui32RefCount;
+} PVR_DEBUGFS_DIR_DATA;
+typedef struct _PVR_DEBUGFS_ENTRY_DATA_
+{
+       struct dentry *psEntry;
+       PVR_DEBUGFS_DIR_DATA *psParentDir;
+       IMG_UINT32      ui32RefCount;
+       PVR_DEBUGFS_DRIVER_STAT *psStatData;
+} PVR_DEBUGFS_ENTRY_DATA;
+typedef struct _PVR_DEBUGFS_PRIV_DATA_
+{
+       struct seq_operations   *psReadOps;
+       PVRSRV_ENTRY_WRITE_FUNC *pfnWrite;
+       void                    *pvData;
+       IMG_BOOL                bValid;
+       PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
+} PVR_DEBUGFS_PRIV_DATA;
+static void _RefDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry);
+static void _UnrefAndMaybeDestroyDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry);
+static void _UnrefAndMaybeDestroyDirEntryWhileLocked(PVR_DEBUGFS_DIR_DATA *psDirEntry);
+static IMG_BOOL _RefDebugFSEntryNoLock(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry);
+static void _UnrefAndMaybeDestroyDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry);
+static IMG_BOOL _RefStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry);
+static IMG_BOOL _UnrefAndMaybeDestroyStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry);
 
 static void *_DebugFSStatisticSeqStart(struct seq_file *psSeqFile, loff_t *puiPosition)
 {
        PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
-       IMG_BOOL bResult;
+       IMG_BOOL bResult = IMG_FALSE;
+
+       if (psStatData)
+       {
+               if (psStatData->pvData)
+               {
+                       /* take reference on psStatData (for duration of stat iteration) */
+                       if (!_RefStatEntry((void*)psStatData))
 
-       bResult = psStatData->pfnGetNextStat(psStatData->pvData,
-                                           (IMG_UINT32)(*puiPosition),
-                                           &psStatData->i32StatValue,
-                                           &psStatData->pszStatFormat);
+                       {
+                               return NULL;
+                       }
+
+               }
+               bResult = psStatData->pfnGetNextStat(psStatData->pvData,
+                                                       (IMG_UINT32)(*puiPosition),
+                                                       &psStatData->i32StatValue,
+                                                       &psStatData->pszStatFormat);
+       }
 
        return bResult ? psStatData : NULL;
 }
 
 static void _DebugFSStatisticSeqStop(struct seq_file *psSeqFile, void *pvData)
 {
-       PVR_UNREFERENCED_PARAMETER(psSeqFile);
-       PVR_UNREFERENCED_PARAMETER(pvData);
+       PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
+
+       if (psStatData)
+       {
+               /* drop ref taken on stat memory, and if it is now zero, be sure we don't try to read it again */
+               if ((psStatData->ui32RefCount > 0) && (psStatData->pvData))
+               {
+                       /* drop reference on psStatData (held for duration of stat iteration) */
+                       _UnrefAndMaybeDestroyStatEntry((void*)psStatData);
+               }
+       }
 }
 
 static void *_DebugFSStatisticSeqNext(struct seq_file *psSeqFile,
-                                     void *pvData,
-                                     loff_t *puiPosition)
+                                         void *pvData,
+                                         loff_t *puiPosition)
 {
        PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)psSeqFile->private;
-       IMG_BOOL bResult;
-
-       (*puiPosition)++;
+       IMG_BOOL bResult = IMG_FALSE;
 
-       bResult = psStatData->pfnGetNextStat(psStatData->pvData,
-                                           (IMG_UINT32)(*puiPosition),
-                                           &psStatData->i32StatValue,
-                                           &psStatData->pszStatFormat);
+       if (puiPosition)
+       {
+               (*puiPosition)++;
 
+               if (psStatData)
+               {
+                       if (psStatData->pvData)
+                       {
+                               bResult = psStatData->pfnGetNextStat(psStatData->pvData,
+                                                                       (IMG_UINT32)(*puiPosition),
+                                                                       &psStatData->i32StatValue,
+                                                                       &psStatData->pszStatFormat);
+                       }
+               }
+       }
        return bResult ? psStatData : NULL;
 }
 
@@ -131,26 +193,81 @@ static struct seq_operations gsDebugFSStatisticReadOps =
  Common internal API
 */ /**************************************************************************/
 
-typedef struct _PVR_DEBUGFS_PRIV_DATA_
+static int _DebugFSFileOpen(struct inode *psINode, struct file *psFile)
 {
-       struct seq_operations   *psReadOps;
-       PVRSRV_ENTRY_WRITE_FUNC *pfnWrite;
-       void                    *pvData;
-} PVR_DEBUGFS_PRIV_DATA;
+       PVR_DEBUGFS_PRIV_DATA *psPrivData;
+       int iResult = -EIO;
+       IMG_BOOL bRefRet = IMG_FALSE;
+       PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry = NULL;
 
-static int _DebugFSFileOpen(struct inode *psINode, struct file *psFile)
+       mutex_lock(&gDebugFSLock);
+
+       PVR_ASSERT(psINode);
+       psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
+       if (psPrivData)
+       {
+               /* Check that psPrivData is still valid to use */
+               if (psPrivData->bValid)
+               {
+                       psDebugFSEntry = psPrivData->psDebugFSEntry;
+
+                       /* Take ref on stat entry before opening seq file - this ref will be dropped if we
+                        * fail to open the seq file or when we close it
+                        */
+                       if (psDebugFSEntry)
+                       {
+                               bRefRet = _RefDebugFSEntryNoLock(psDebugFSEntry);
+                               mutex_unlock(&gDebugFSLock);
+                               if (bRefRet)
+                               {
+                                       iResult = seq_open(psFile, psPrivData->psReadOps);
+                                       if (iResult == 0)
+                                       {
+                                               struct seq_file *psSeqFile = psFile->private_data;
+
+                                               psSeqFile->private = psPrivData->pvData;
+                                       }
+                                       else
+                                       {
+                                               /* Drop ref if we failed to open seq file */
+                                               _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
+                                               PVR_DPF((PVR_DBG_ERROR, "%s: Failed to seq_open psFile, returning %d", __FUNCTION__, iResult));
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               mutex_unlock(&gDebugFSLock);
+                       }
+               }
+               else
+               {
+                       mutex_unlock(&gDebugFSLock);
+               }
+       }
+       else
+       {
+               mutex_unlock(&gDebugFSLock);
+       }
+
+       return iResult;
+}
+
+static int _DebugFSFileClose(struct inode *psINode, struct file *psFile)
 {
-       PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
        int iResult;
+       PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA *)psINode->i_private;
+       PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry = NULL;
 
-       iResult = seq_open(psFile, psPrivData->psReadOps);
-       if (iResult == 0)
+       if (psPrivData)
        {
-               struct seq_file *psSeqFile = psFile->private_data;
-
-               psSeqFile->private = psPrivData->pvData;
+               psDebugFSEntry = psPrivData->psDebugFSEntry;
+       }
+       iResult = seq_release(psINode, psFile);
+       if (psDebugFSEntry)
+       {
+               _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
        }
-
        return iResult;
 }
 
@@ -164,6 +281,7 @@ static ssize_t _DebugFSFileWrite(struct file *psFile,
 
        if (psPrivData->pfnWrite == NULL)
        {
+               PVR_DPF((PVR_DBG_ERROR, "%s: Called for file '%s', which does not have pfnWrite defined, returning -EIO(%d)", __FUNCTION__, psFile->f_path.dentry->d_iname, -EIO));
                return -EIO;
        }
 
@@ -177,7 +295,7 @@ static const struct file_operations gsPVRDebugFSFileOps =
        .read = seq_read,
        .write = _DebugFSFileWrite,
        .llseek = seq_lseek,
-       .release = seq_release,
+       .release = _DebugFSFileClose,
 };
 
 
@@ -196,6 +314,8 @@ int PVRDebugFSInit(void)
 {
        PVR_ASSERT(gpsPVRDebugFSEntryDir == NULL);
 
+       mutex_init(&gDebugFSLock);
+
        gpsPVRDebugFSEntryDir = debugfs_create_dir(PVR_DEBUGFS_DIR_NAME, NULL);
        if (gpsPVRDebugFSEntryDir == NULL)
        {
@@ -223,6 +343,7 @@ void PVRDebugFSDeInit(void)
 
        debugfs_remove(gpsPVRDebugFSEntryDir);
        gpsPVRDebugFSEntryDir = NULL;
+       mutex_destroy(&gDebugFSLock);
 }
 
 /*************************************************************************/ /*!
@@ -242,31 +363,50 @@ void PVRDebugFSDeInit(void)
                              error code.
 */ /**************************************************************************/
 int PVRDebugFSCreateEntryDir(IMG_CHAR *pszName,
-                            struct dentry *psParentDir,
-                            struct dentry **ppsDir)
+                                PVR_DEBUGFS_DIR_DATA *psParentDir,
+                                PVR_DEBUGFS_DIR_DATA **ppsNewDir)
 {
-       struct dentry *psDir;
+       PVR_DEBUGFS_DIR_DATA *psNewDir;
 
        PVR_ASSERT(gpsPVRDebugFSEntryDir != NULL);
 
-       if (pszName == NULL || ppsDir == NULL)
+       if (pszName == NULL || ppsNewDir == NULL)
        {
+               PVR_DPF((PVR_DBG_ERROR, "%s:   Invalid param", __FUNCTION__));
                return -EINVAL;
        }
 
-       psDir = debugfs_create_dir(pszName,
-                                  (psParentDir) ? psParentDir : gpsPVRDebugFSEntryDir);
-       if (psDir == NULL)
+       psNewDir = kmalloc(sizeof(*psNewDir), GFP_KERNEL);
+
+       if (psNewDir == IMG_NULL)
+       {
+               PVR_DPF((PVR_DBG_ERROR,
+                        "%s: Cannot allocate memory for '%s' pvr_debugfs structure",
+                        __FUNCTION__, pszName));
+               return -ENOMEM;
+       }
+
+       psNewDir->psParentDir = psParentDir;
+       psNewDir->psDir = debugfs_create_dir(pszName, (psNewDir->psParentDir) ? psNewDir->psParentDir->psDir : gpsPVRDebugFSEntryDir);
+
+       if (psNewDir->psDir == NULL)
        {
                PVR_DPF((PVR_DBG_ERROR,
                         "%s: Cannot create '%s' debugfs directory",
                         __FUNCTION__, pszName));
 
+               kfree(psNewDir);
                return -ENOMEM;
        }
 
-       *ppsDir = psDir;
+       *ppsNewDir = psNewDir;
+       psNewDir->ui32RefCount = 1;
 
+       /* if parent directory is not gpsPVRDebugFSEntryDir, increment its refCount */
+       if (psNewDir->psParentDir)
+       {
+               _RefDirEntry(psNewDir->psParentDir);
+       }
        return 0;
 }
 
@@ -278,16 +418,16 @@ int PVRDebugFSCreateEntryDir(IMG_CHAR *pszName,
 @Input          psDir        Pointer representing the directory to be removed.
 @Return         void
 */ /**************************************************************************/
-void PVRDebugFSRemoveEntryDir(struct dentry *psDir)
+void PVRDebugFSRemoveEntryDir(PVR_DEBUGFS_DIR_DATA *psDir)
 {
-       debugfs_remove(psDir);
+       _UnrefAndMaybeDestroyDirEntry(psDir);
 }
 
 /*************************************************************************/ /*!
 @Function       PVRDebugFSCreateEntry
 @Description    Create an entry in the specified directory.
 @Input          pszName         String containing the name for the entry.
-@Input          pvDir           Pointer from PVRDebugFSCreateEntryDir()
+@Input          psParentDir     Pointer from PVRDebugFSCreateEntryDir()
                                 representing the directory in which to create
                                 the entry or NULL for the root directory.
 @Input          psReadOps       Pointer to structure containing the necessary
@@ -296,18 +436,19 @@ void PVRDebugFSRemoveEntryDir(struct dentry *psDir)
 @Input          pvData          Private data to be passed to the read
                                 functions, in the seq_file private member, and
                                 the write function callback.
-@Output         ppsEntry        On success, points to the newly created entry.
+@Output         ppsNewEntry     On success, points to the newly created entry.
 @Return         int             On success, returns 0. Otherwise, returns an
                                 error code.
 */ /**************************************************************************/
 int PVRDebugFSCreateEntry(const char *pszName,
-                         void *pvDir,
+                         PVR_DEBUGFS_DIR_DATA *psParentDir,
                          struct seq_operations *psReadOps,
                          PVRSRV_ENTRY_WRITE_FUNC *pfnWrite,
                          void *pvData,
-                         struct dentry **ppsEntry)
+                         PVR_DEBUGFS_ENTRY_DATA **ppsNewEntry)
 {
        PVR_DEBUGFS_PRIV_DATA *psPrivData;
+       PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
        struct dentry *psEntry;
        umode_t uiMode;
 
@@ -318,10 +459,20 @@ int PVRDebugFSCreateEntry(const char *pszName,
        {
                return -ENOMEM;
        }
+       psDebugFSEntry = kmalloc(sizeof(*psDebugFSEntry), GFP_KERNEL);
+       if (psDebugFSEntry == NULL)
+       {
+               kfree(psPrivData);
+               return -ENOMEM;
+       }
 
        psPrivData->psReadOps = psReadOps;
        psPrivData->pfnWrite = pfnWrite;
-       psPrivData->pvData = pvData;
+       psPrivData->pvData = (void*)pvData;
+       psPrivData->bValid = IMG_TRUE;
+       /* Store ptr to debugFSEntry in psPrivData, so a ref can be taken on it
+        * when the client opens a file */
+       psPrivData->psDebugFSEntry = psDebugFSEntry;
 
        uiMode = S_IFREG;
 
@@ -335,9 +486,19 @@ int PVRDebugFSCreateEntry(const char *pszName,
                uiMode |= S_IWUSR;
        }
 
+       psDebugFSEntry->psParentDir = psParentDir;
+       psDebugFSEntry->ui32RefCount = 1;
+       psDebugFSEntry->psStatData = (PVR_DEBUGFS_DRIVER_STAT*)pvData;
+
+       if (psDebugFSEntry->psParentDir)
+       {
+               /* increment refCount of parent directory */
+               _RefDirEntry(psDebugFSEntry->psParentDir);
+       }
+
        psEntry = debugfs_create_file(pszName,
                                      uiMode,
-                                     (pvDir != NULL) ? (struct dentry *)pvDir : gpsPVRDebugFSEntryDir,
+                                     (psParentDir != NULL) ? psParentDir->psDir : gpsPVRDebugFSEntryDir,
                                      psPrivData,
                                      &gsPVRDebugFSFileOps);
        if (IS_ERR(psEntry))
@@ -349,11 +510,8 @@ int PVRDebugFSCreateEntry(const char *pszName,
                return PTR_ERR(psEntry);
        }
 
-       /* take reference on inode (for allocation held in d_inode->i_private) - stops
-        * inode being removed until we have freed the memory allocated in i_private */
-       igrab(psEntry->d_inode);
-
-       *ppsEntry = psEntry;
+       psDebugFSEntry->psEntry = psEntry;
+       *ppsNewEntry = (void*)psDebugFSEntry;
 
        return 0;
 }
@@ -361,94 +519,273 @@ int PVRDebugFSCreateEntry(const char *pszName,
 /*************************************************************************/ /*!
 @Function       PVRDebugFSRemoveEntry
 @Description    Removes an entry that was created by PVRDebugFSCreateEntry().
-@Input          psEntry  Pointer representing the entry to be removed.
+@Input          psDebugFSEntry  Pointer representing the entry to be removed.
 @Return         void
 */ /**************************************************************************/
-void PVRDebugFSRemoveEntry(struct dentry *psEntry)
+void PVRDebugFSRemoveEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
 {
-       if(psEntry != IMG_NULL)
-       {
-               /* Free any private data that was provided to debugfs_create_file() */
-               if (psEntry->d_inode->i_private != NULL)
-               {
-                       kfree(psEntry->d_inode->i_private);
-                       /* drop reference on inode now that we have freed the allocated memory*/
-                       iput(psEntry->d_inode);
-               }
-
-               debugfs_remove(psEntry);
-       }
+       _UnrefAndMaybeDestroyDebugFSEntry(psDebugFSEntry);
 }
 
 /*************************************************************************/ /*!
 @Function       PVRDebugFSCreateStatisticEntry
 @Description    Create a statistic entry in the specified directory.
 @Input          pszName         String containing the name for the entry.
-@Input          pvDir           Pointer from PVRDebugFSCreateEntryDir()
+@Input          psDir           Pointer from PVRDebugFSCreateEntryDir()
                                 representing the directory in which to create
                                 the entry or NULL for the root directory.
-@Input          pfnGetNextStat  A callback function used to get the next
-                                statistic when reading from the statistic
+@Input          pfnStatsPrint   A callback function used to print all the
+                                statistics when reading from the statistic
                                 entry.
+@Input          pfnIncStatMemRefCount   A callback function used take a
+                                                                               reference on the memory backing the
+                                               statistic.
+@Input          pfnDecStatMemRefCount   A callback function used drop a
+                                                                               reference on the memory backing the
+                                               statistic.
 @Input          pvData          Private data to be passed to the provided
                                 callback function.
-@Return         void *          On success, a pointer representing the newly
-                                created statistic entry. Otherwise, NULL.
+
+@Return         PVR_DEBUGFS_DRIVER_STAT*   On success, a pointer representing
+                                                                                  the newly created statistic entry.
+                                                                                  Otherwise, NULL.
 */ /**************************************************************************/
-void *PVRDebugFSCreateStatisticEntry(const char *pszName,
-                                    void *pvDir,
+PVR_DEBUGFS_DRIVER_STAT *PVRDebugFSCreateStatisticEntry(const char *pszName,
+                                        PVR_DEBUGFS_DIR_DATA *psDir,
                                     PVRSRV_GET_NEXT_STAT_FUNC *pfnGetNextStat,
-                                    void *pvData)
+                                        PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC      *pfnIncStatMemRefCount,
+                                        PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC      *pfnDecStatMemRefCount,
+                                        void *pvData)
 {
        PVR_DEBUGFS_DRIVER_STAT *psStatData;
+       PVR_DEBUGFS_ENTRY_DATA * psDebugFSEntry;
        int iResult;
 
        if (pszName == NULL || pfnGetNextStat == NULL)
        {
                return NULL;
        }
+       if ((pfnIncStatMemRefCount != NULL || pfnDecStatMemRefCount != NULL) && pvData == NULL)
+       {
+               return NULL;
+       }
 
        psStatData = kzalloc(sizeof(*psStatData), GFP_KERNEL);
        if (psStatData == NULL)
        {
                return NULL;
        }
-
        psStatData->pvData = pvData;
        psStatData->pfnGetNextStat = pfnGetNextStat;
+       psStatData->pfnIncStatMemRefCount = pfnIncStatMemRefCount;
+       psStatData->pfnDecStatMemRefCount = pfnDecStatMemRefCount;
+       psStatData->ui32RefCount = 1;
 
        iResult = PVRDebugFSCreateEntry(pszName,
-                                       pvDir,
+                                       psDir,
                                        &gsDebugFSStatisticReadOps,
                                        NULL,
                                        psStatData,
-                                       &psStatData->psEntry);
+                                       &psDebugFSEntry);
        if (iResult != 0)
        {
                kfree(psStatData);
                return NULL;
        }
+       psStatData->pvDebugFSEntry = (void*)psDebugFSEntry;
+
+       if (pfnIncStatMemRefCount)
+       {
+               /* call function to take reference on the memory holding the stat */
+               psStatData->pfnIncStatMemRefCount((void*)psStatData->pvData);
+       }
+
+       psDebugFSEntry->ui32RefCount = 1;
 
-       return psStatData;
+    return psStatData;
 }
 
 /*************************************************************************/ /*!
 @Function       PVRDebugFSRemoveStatisticEntry
 @Description    Removes a statistic entry that was created by
                 PVRDebugFSCreateStatisticEntry().
-@Input          pvEntry  Pointer representing the statistic entry to be
-                         removed.
+@Input          psStatEntry  Pointer representing the statistic entry to be
+                                removed.
 @Return         void
 */ /**************************************************************************/
-void PVRDebugFSRemoveStatisticEntry(void *pvStatEntry)
+void PVRDebugFSRemoveStatisticEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
 {
-       PVR_DEBUGFS_DRIVER_STAT *psStatData = (PVR_DEBUGFS_DRIVER_STAT *)pvStatEntry;
+       /* drop reference on pvStatEntry*/
+       _UnrefAndMaybeDestroyStatEntry(psStatEntry);
+}
 
-       if (psStatData != NULL)
+static void _RefDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry)
+{
+       mutex_lock(&gDebugFSLock);
+
+       if (psDirEntry->ui32RefCount > 0)
        {
-               PVRDebugFSRemoveEntry(psStatData->psEntry);
+               /* Increment refCount */
+               psDirEntry->ui32RefCount++;
+       }
 
-               kfree(psStatData);
+       mutex_unlock(&gDebugFSLock);
+}
+
+static void _UnrefAndMaybeDestroyDirEntryWhileLocked(PVR_DEBUGFS_DIR_DATA *psDirEntry)
+{
+       if (psDirEntry->ui32RefCount > 0)
+       {
+               /* Decrement refCount and free if now zero */
+               if (--psDirEntry->ui32RefCount == 0)
+               {
+                       /* if parent directory is not gpsPVRDebugFSEntryDir, decrement its refCount */
+                       debugfs_remove(psDirEntry->psDir);
+                       if (psDirEntry->psParentDir)
+                       {
+                               _UnrefAndMaybeDestroyDirEntryWhileLocked(psDirEntry->psParentDir);
+                       }
+                       kfree(psDirEntry);
+               }
+       }
+}
+
+static void _UnrefAndMaybeDestroyDirEntry(PVR_DEBUGFS_DIR_DATA *psDirEntry)
+{
+       mutex_lock(&gDebugFSLock);
+
+       if (psDirEntry->ui32RefCount > 0)
+       {
+               /* Decrement refCount and free if now zero */
+               if (--psDirEntry->ui32RefCount == 0)
+               {
+                       /* if parent directory is not gpsPVRDebugFSEntryDir, decrement its refCount */
+                       debugfs_remove(psDirEntry->psDir);
+                       if (psDirEntry->psParentDir)
+                       {
+                               _UnrefAndMaybeDestroyDirEntryWhileLocked(psDirEntry->psParentDir);
+                       }
+                       kfree(psDirEntry);
+               }
+       }
+
+       mutex_unlock(&gDebugFSLock);
+}
+
+static IMG_BOOL _RefDebugFSEntryNoLock(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
+{
+       IMG_BOOL bResult = IMG_FALSE;
+
+       PVR_ASSERT(psDebugFSEntry != NULL);
+
+       bResult = (psDebugFSEntry->ui32RefCount > 0);
+       if (bResult)
+       {
+               /* Increment refCount of psDebugFSEntry */
+               psDebugFSEntry->ui32RefCount++;
+       }
+
+       return bResult;
+}
+
+static void _UnrefAndMaybeDestroyDebugFSEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry)
+{
+       mutex_lock(&gDebugFSLock);
+       /* Decrement refCount of psDebugFSEntry, and free if now zero */
+       PVR_ASSERT(psDebugFSEntry != IMG_NULL);
+
+       if (psDebugFSEntry->ui32RefCount > 0)
+       {
+               if (--psDebugFSEntry->ui32RefCount == 0)
+               {
+                       struct dentry *psEntry = psDebugFSEntry->psEntry;
+
+                       if (psEntry)
+                       {
+                               /* Free any private data that was provided to debugfs_create_file() */
+                               if (psEntry->d_inode->i_private != NULL)
+                               {
+                                       PVR_DEBUGFS_PRIV_DATA *psPrivData = (PVR_DEBUGFS_PRIV_DATA*)psDebugFSEntry->psEntry->d_inode->i_private;
+
+                                       psPrivData->bValid = IMG_FALSE;
+                                       psPrivData->psDebugFSEntry = NULL;
+                                       kfree(psEntry->d_inode->i_private);
+                                       psEntry->d_inode->i_private = IMG_NULL;
+                               }
+                               debugfs_remove(psEntry);
+                       }
+
+                       /* decrement refcount of parent directory */
+                       if (psDebugFSEntry->psParentDir)
+                       {
+                               _UnrefAndMaybeDestroyDirEntryWhileLocked(psDebugFSEntry->psParentDir);
+                       }
+
+                       /* now free the memory allocated for psDebugFSEntry */
+                       kfree(psDebugFSEntry);
+               }
        }
+
+       mutex_unlock(&gDebugFSLock);
+
 }
 
+static IMG_BOOL _RefStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
+{
+       IMG_BOOL bResult = IMG_FALSE;
+
+       PVR_ASSERT(psStatEntry != NULL);
+
+       mutex_lock(&gDebugFSLock);
+
+       bResult = (psStatEntry->ui32RefCount > 0);
+       if (bResult)
+       {
+               /* Increment refCount of psStatEntry */
+               psStatEntry->ui32RefCount++;
+       }
+
+       mutex_unlock(&gDebugFSLock);
+
+       return bResult;
+}
+
+static IMG_BOOL _UnrefAndMaybeDestroyStatEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
+{
+       IMG_BOOL bResult;
+
+       PVR_ASSERT(psStatEntry != IMG_NULL);
+
+       mutex_lock(&gDebugFSLock);
+
+       bResult = (psStatEntry->ui32RefCount > 0);
+
+       if (bResult)
+       {
+               /* Decrement refCount of psStatData, and free if now zero */
+               if (--psStatEntry->ui32RefCount == 0)
+               {
+                       mutex_unlock(&gDebugFSLock);
+
+                       if (psStatEntry->pvDebugFSEntry)
+                       {
+                               _UnrefAndMaybeDestroyDebugFSEntry((PVR_DEBUGFS_ENTRY_DATA*)psStatEntry->pvDebugFSEntry);
+                       }
+                       if (psStatEntry->pfnDecStatMemRefCount)
+                       {
+                               /* call function to drop reference on the memory holding the stat */
+                               psStatEntry->pfnDecStatMemRefCount((void*)psStatEntry->pvData);
+                       }
+               }
+               else
+               {
+                       mutex_unlock(&gDebugFSLock);
+               }
+       }
+       else
+       {
+               mutex_unlock(&gDebugFSLock);
+       }
+
+       return bResult;
+}
index 7ac45888bf664985915c53e5fe2648d5e4925370..3b3f52e78cee67af37ab106900167bfd094cc80f 100644 (file)
@@ -58,26 +58,37 @@ typedef IMG_BOOL (PVRSRV_GET_NEXT_STAT_FUNC)(void *pvStatPtr,
                                             IMG_INT32 *piStatData,
                                             IMG_CHAR **ppszStatFmtText);
 
+typedef IMG_UINT32 (PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC)(void *pvStatPtr);
+typedef IMG_UINT32 (PVRSRV_DEC_STAT_MEM_REFCOUNT_FUNC)(void *pvStatPtr);
+
+typedef struct _PVR_DEBUGFS_DIR_DATA_ PVR_DEBUGFS_DIR_DATA;
+typedef struct _PVR_DEBUGFS_ENTRY_DATA_ PVR_DEBUGFS_ENTRY_DATA;
+typedef struct _PVR_DEBUGFS_DRIVER_STAT_ PVR_DEBUGFS_DRIVER_STAT;
+
 int PVRDebugFSInit(void);
 void PVRDebugFSDeInit(void);
 
 int PVRDebugFSCreateEntryDir(IMG_CHAR *pszName,
-                            struct dentry *psParentDir,
-                            struct dentry **ppsDir);
-void PVRDebugFSRemoveEntryDir(struct dentry *psDir);
+                                                        PVR_DEBUGFS_DIR_DATA *psParentDir,
+                                                        PVR_DEBUGFS_DIR_DATA **ppsNewDir);
+
+void PVRDebugFSRemoveEntryDir(PVR_DEBUGFS_DIR_DATA *psDir);
 
 int PVRDebugFSCreateEntry(const char *pszName,
-                         void *pvDir,
-                         struct seq_operations *psReadOps,
-                         PVRSRV_ENTRY_WRITE_FUNC *pfnWrite,
-                         void *pvData,
-                         struct dentry **ppsEntry);
-void PVRDebugFSRemoveEntry(struct dentry *psEntry);
-
-void *PVRDebugFSCreateStatisticEntry(const char *pszName,
-                                    void *pvDir,
-                                    PVRSRV_GET_NEXT_STAT_FUNC *pfnGetNextStat,
-                                    void *pvData);
-void PVRDebugFSRemoveStatisticEntry(void *pvStatEntry);
+                                                 PVR_DEBUGFS_DIR_DATA *psParentDir,
+                                                 struct seq_operations *psReadOps,
+                                                 PVRSRV_ENTRY_WRITE_FUNC *pfnWrite,
+                                                 void *pvData,
+                                                 PVR_DEBUGFS_ENTRY_DATA **ppsNewEntry);
+
+void PVRDebugFSRemoveEntry(PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry);
+
+PVR_DEBUGFS_DRIVER_STAT *PVRDebugFSCreateStatisticEntry(const char *pszName,
+                                                                                                               PVR_DEBUGFS_DIR_DATA *psDir,
+                                                                                                               PVRSRV_GET_NEXT_STAT_FUNC *pfnGetNextStat,
+                                                                                                               PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC       *pfnIncStatMemRefCount,
+                                                                                                               PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC       *pfnDecStatMemRefCount,
+                                                                                                               void *pvData);
+void PVRDebugFSRemoveStatisticEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry);
 
 #endif /* !defined(__PVR_DEBUGFS_H__) */
index 9bb0e920c972859a46db9e164a5debb52cce5602..06adc642971d0b3ca1f844f9e43e9c2830a0755a 100644 (file)
@@ -197,7 +197,7 @@ static PVRSRV_ERROR GetCtxAndJobID(IMG_UINT32 ui32PID,
 
 
 /* DebugFS entry for the feature's on/off file */
-static struct dentry* gpsPVRDebugFSGpuTracingOnEntry = NULL;
+static PVR_DEBUGFS_ENTRY_DATA *gpsPVRDebugFSGpuTracingOnEntry = NULL;
 
 
 /*
@@ -291,8 +291,14 @@ static IMG_INT GpuTracingSet(const IMG_CHAR *buffer, size_t count, loff_t uiPosi
                case 'y':
                case 'Y':
                {
-                       PVRGpuTraceEnabledSet(IMG_TRUE);
-                       PVR_TRACE(("ENABLED GPU FTrace"));
+                       if (PVRGpuTraceEnabledSet(IMG_TRUE) == PVRSRV_OK)
+                       {
+                               PVR_TRACE(("ENABLED GPU FTrace"));
+                       }
+                       else
+                       {
+                               PVR_TRACE(("FAILED to enable GPU FTrace"));
+                       }
                        break;
                }
        }
@@ -388,17 +394,17 @@ PVRSRV_ERROR PVRGpuTraceInit(void)
                                      &gsGpuTracingReadOps,
                                      (PVRSRV_ENTRY_WRITE_FUNC *)GpuTracingSet,
                                      NULL,
-                                     &gpsPVRDebugFSGpuTracingOnEntry);
+                      &gpsPVRDebugFSGpuTracingOnEntry);
 }
 
 
 void PVRGpuTraceDeInit(void)
 {
        /* Can be NULL if driver startup failed */
-       if (gpsPVRDebugFSGpuTracingOnEntry)
+    if (gpsPVRDebugFSGpuTracingOnEntry)
        {
-               PVRDebugFSRemoveEntry(gpsPVRDebugFSGpuTracingOnEntry);
-               gpsPVRDebugFSGpuTracingOnEntry = NULL;
+        PVRDebugFSRemoveEntry(gpsPVRDebugFSGpuTracingOnEntry);
+        gpsPVRDebugFSGpuTracingOnEntry = NULL;
        }
 }
 
index b681bbe64636a8913a9fd4d5559ec866fe793a1d..e4f21ee86309dbaadc51dd08e63add46562fa618 100644 (file)
@@ -54,7 +54,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   The device layer of the KM driver defines these two APIs to allow a
   platform module to set and retrieve the feature's on/off state.
 */
-extern void PVRGpuTraceEnabledSet(IMG_BOOL bNewValue);
+extern PVRSRV_ERROR PVRGpuTraceEnabledSet(IMG_BOOL bNewValue);
 extern IMG_BOOL PVRGpuTraceEnabled(void);
 
 
index 0183527561b06e7cb8d62c1d974c67ed85bae60f..3d7e006a1b1f67c14e4eccee2ddbeea41030c3f6 100644 (file)
@@ -414,8 +414,13 @@ typedef IMG_BOOL (OS_GET_STATS_ELEMENT_FUNC)(IMG_PVOID pvStatPtr,
                                              IMG_INT32* pi32StatData,
                                              IMG_CHAR** ppszStatFmtText);
 
+typedef IMG_UINT32 (OS_INC_STATS_MEM_REFCOUNT_FUNC)(IMG_PVOID pvStatPtr);
+typedef IMG_UINT32 (OS_DEC_STATS_MEM_REFCOUNT_FUNC)(IMG_PVOID pvStatPtr);
+
 IMG_PVOID OSCreateStatisticEntry(IMG_CHAR* pszName, IMG_PVOID pvFolder,
                                  OS_GET_STATS_ELEMENT_FUNC* pfnGetElement,
+                                                                OS_INC_STATS_MEM_REFCOUNT_FUNC* pfnIncMemRefCt,
+                                                                OS_DEC_STATS_MEM_REFCOUNT_FUNC* pfnDecMemRefCt,
                                  IMG_PVOID pvData);
 IMG_VOID OSRemoveStatisticEntry(IMG_PVOID pvEntry);
 IMG_PVOID OSCreateStatisticFolder(IMG_CHAR *pszName, IMG_PVOID pvFolder);
index 1a15a72de3f46f38c88abec1dab951c7eab4e80e..d6c3b18bc8494209cec9d61a8a225ec54264564c 100644 (file)
@@ -94,6 +94,7 @@ typedef struct PVRSRV_DATA_TAG
 
        IMG_HANDLE                                      hCleanupThread;                         /*!< Cleanup thread */
        IMG_HANDLE                                      hCleanupEventObject;            /*!< Event object to drive cleanup thread */
+       IMG_PID                                         cleanupThreadPid;                       /*!< Cleanup thread process id */
 
        IMG_HANDLE                                      hDevicesWatchdogThread;         /*!< Devices Watchdog thread */
        IMG_HANDLE                                      hDevicesWatchdogEvObj;          /*! Event object to drive devices watchdog thread */
index 76c41bb7bd3921b7445dcc57a70bb4d06755a449..4f81b865f558f7a45bf713781de5f2365428ed51 100644 (file)
@@ -49,6 +49,7 @@ extern "C" {
 #endif
 
 #include "servicesext.h"
+#include "dllist.h"
 
 /******************************************************************************
  * resman definitions 
@@ -138,6 +139,13 @@ typedef struct _RESMAN_ITEM_ *PRESMAN_ITEM;
 typedef struct _RESMAN_CONTEXT_ *PRESMAN_CONTEXT;
 typedef struct _RESMAN_DEFER_CONTEXTS_LIST_ *PRESMAN_DEFER_CONTEXTS_LIST;
 
+typedef struct _RESMAN_FREE_FN_AND_DATA_
+{
+       DLLIST_NODE sNode;
+       RESMAN_FREE_FN pfnFree;
+       IMG_VOID *pvParam;
+} RESMAN_FREE_FN_AND_DATA;
+
 /******************************************************************************
  * resman functions 
  *****************************************************************************/
@@ -187,6 +195,10 @@ IMG_BOOL PVRSRVResManFlushDeferContext(PRESMAN_DEFER_CONTEXTS_LIST hDeferContext
 
 IMG_VOID PVRSRVResManDestroyDeferContext(PRESMAN_DEFER_CONTEXTS_LIST hDeferContext);
 
+IMG_VOID PVRSRVResManAddNoBridgeLockCallback(RESMAN_FREE_FN_AND_DATA *psCallbackInfo);
+
+IMG_BOOL PVRSRVResManInDeferredCleanup(IMG_VOID);
+
 #if defined (__cplusplus)
 }
 #endif
index b4d49d67fd4b540606126f77cd1c3626538f2efb..7490fe9a31b37f31aebf781a87a37be1e4f9d6ca 100755 (executable)
@@ -1081,19 +1081,7 @@ DevmemAllocate(DEVMEM_HEAP *psHeap,
                PVR_ASSERT(uiSize<IMG_UINT32_MAX);
 #endif
 
-#if defined(CONFIG_ARM64) || defined(__arm64__) || defined(__aarch64__)
-               {
-                       IMG_UINT32 i;
-                       IMG_BYTE * pbyPtr;
-
-                       pbyPtr = (IMG_BYTE*) pvAddr;
-                       for (i = 0; i < uiSize; i++)
-                               *pbyPtr++ = 0;
-               }
-
-#else
                OSMemSet(pvAddr, 0x0, (IMG_SIZE_T) uiSize);
-#endif
            
                DevmemReleaseCpuVirtAddr(psMemDesc);
 
index 0d54ed69989ee26e9f074d528660dde3f2314134..35b734c88e938bbf4898274934ac4faf11462d22 100644 (file)
@@ -50,7 +50,7 @@ typedef struct _FLASH_DATA_
        IMG_UINT32                      ui32ReadEntry;
        IMG_BOOL                        bEnteredResetMode;
 
-       struct dentry                   *debugFSEntry;
+       PVR_DEBUGFS_ENTRY_DATA          *psDebugFSEntry;
        PFN_APOLLO_FLASH_INIT           pfnFlashInit;
        PFN_APOLLO_FLASH_WRITE          pfnFlashWrite;
        PFN_APOLLO_FLASH_GET_STATUS     pfnFlashGetStatus;
@@ -221,7 +221,7 @@ PVRSRV_ERROR ApolloFlasherSetup(IMG_HANDLE *phFlasher,
                                  &gsFlasherReadOps,
                                  (PVRSRV_ENTRY_WRITE_FUNC *)ApolloFlashWrite,
                                  (IMG_VOID *)psApolloFlashData,
-                                 &psApolloFlashData->debugFSEntry) < 0)
+                                 &psApolloFlashData->psDebugFSEntry) < 0)
        {
                OSFreeMem(psApolloFlashData);
 
@@ -239,9 +239,9 @@ PVRSRV_ERROR ApolloFlasherCleanup(IMG_HANDLE hFlasher)
 
        if (psFlashData != IMG_NULL)
        {
-               if (psFlashData->debugFSEntry != NULL)
+               if (psFlashData->psDebugFSEntry != NULL)
                {
-                       PVRDebugFSRemoveEntry(psFlashData->debugFSEntry);
+                       PVRDebugFSRemoveEntry(psFlashData->psDebugFSEntry);
                }
 
                OSFreeMem(hFlasher);
index cffac0a0080bf57b6c1859fc1f3d7c042d9bd789..28d2143b08782f9bee5d4713997734e0fc4a378b 100755 (executable)
 #include "power.h"
 #include "rk_init.h"
 
+#include <asm/compiler.h>
+
+
+#if RK_TF_VERSION
+#define PSCI_RKSIP_TF_VERSION (0x82000001)
+
+
+static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
+      u64 arg2)
+{
+ asm volatile(
+   __asmeq("%0", "x0")
+   __asmeq("%1", "x1")
+   __asmeq("%2", "x2")
+   __asmeq("%3", "x3")
+   "smc #0\n"
+  : "+r" (function_id)
+  : "r" (arg0), "r" (arg1), "r" (arg2));
+
+
+ return function_id;
+}
+
+static int (*invoke_psci_fn)(u64, u64 , u64, u64) = __invoke_psci_fn_smc;
+
+
+static int rk_tf_get_version(void)
+{
+    int ver_num;
+    ver_num = invoke_psci_fn(PSCI_RKSIP_TF_VERSION, 0, 0, 0);
+
+    return ver_num;
+}
+
+static int rk_tf_check_version(void)
+{
+    int version=0;
+    int high_16=0;
+    int low_16=0;
+    IMG_PINT pNULL=NULL;
+
+    version = rk_tf_get_version();
+    high_16 = (version >> 16) & ~(0xFFFF << 16);
+    low_16 = (version & ~(0xFFFF << 16));
+
+    printk("raw version=0x%x,rk_tf_version=%x.%x\n",version,high_16,low_16);
+
+    if((version != 0xFFFFFFFF) && (high_16 >= 1) && (low_16 >= 3))
+    {
+        return 0;
+    }
+    else
+    {
+        printk("Error:%s-line:%d This version cann't support rk3328\n",__func__,__LINE__);
+        *pNULL=0; //crash system
+        return -1;
+    }
+}
+
+#endif
 
 extern struct platform_device *gpsPVRLDMDev;
 
@@ -62,6 +122,7 @@ unsigned int RGX_DVFS_STEP = ARRAY_SIZE(rgx_dvfs_infotbl);
 static int rk33_clk_set_normal_node(struct clk* node, unsigned long rate)
 {
     int ret = 0;
+
     if (!node)
     {
         printk("rk33_clk_set_normal_node error \r\n");
@@ -158,15 +219,20 @@ static void rk33_dvfs_set_clock(int freq)
     if (NULL == platform)
         panic("oops");
 
-    if (!platform->gpu_clk_node || !platform->aclk_gpu_mem || !platform->gpu_clk_node)
+    if ( !platform->aclk_gpu_mem || !platform->aclk_gpu_cfg || !platform->dvfs_enabled)
     {
-        printk("gpu_clk_node not init\n");
+        printk("aclk_gpu_mem or aclk_gpu_cfg not init\n");
         return;
     }
     //mutex_lock(&rgx_set_clock_lock);
     rk33_clk_set_normal_node(platform->aclk_gpu_mem, freq);
     rk33_clk_set_normal_node(platform->aclk_gpu_cfg, freq);
-    rk33_clk_set_dvfs_node(platform->gpu_clk_node, freq);
+
+    if(platform->gpu_clk_node)
+        rk33_clk_set_dvfs_node(platform->gpu_clk_node, freq);
+    else if(platform->clk_gpu)
+        rk33_clk_set_normal_node(platform->clk_gpu, freq);
+
     //mutex_unlock(&rgx_set_clock_lock);
     return;
 }
@@ -784,7 +850,6 @@ static IMG_VOID rk33_dvfs_utils_init(struct rk_context *platform)
     platform->temperature = 0;
     platform->temperature_time = 0;
     platform->timer_active = IMG_FALSE;
-    platform->dvfs_enabled = IMG_TRUE;
 
 #if RK33_USE_CL_COUNT_UTILS
     platform->abs_load[0] = platform->abs_load[1] = platform->abs_load[2] = platform->abs_load[3] = 0;
@@ -799,8 +864,6 @@ static IMG_VOID rk33_dvfs_utils_init(struct rk_context *platform)
 #endif //RK33_DVFS_FREQ_LIMIT
 #endif //RK33_SYSFS_FILE_SUPPORT
 
-    //dvfs timer
-    spin_lock_init(&platform->timer_lock);
 
 #if USE_HRTIMER
     {
@@ -1622,9 +1685,9 @@ IMG_BOOL rk33_set_device_node(IMG_HANDLE hDevCookie)
 
         //start timer
 #if USE_HRTIMER
-        if(platform->psDeviceNode && platform->timer.function && !platform->timer_active)
+        if(platform->psDeviceNode && platform->dvfs_enabled && platform->timer.function && !platform->timer_active)
 #elif USE_KTHREAD
-        if(platform->psDeviceNode && !platform->timer_active)
+        if(platform->psDeviceNode && platform->dvfs_enabled && !platform->timer_active)
 #endif
         {
             spin_lock_irqsave(&platform->timer_lock, flags);
@@ -1657,7 +1720,7 @@ IMG_BOOL rk33_clear_device_node(IMG_VOID)
     if(platform)
     {
         //cacel timer
-        if(platform->timer_active)
+        if(platform->timer_active && platform->dvfs_enabled)
         {
             spin_lock_irqsave(&platform->timer_lock, flags);
             platform->timer_active = IMG_FALSE;
@@ -1683,23 +1746,27 @@ IMG_BOOL rk33_clear_device_node(IMG_VOID)
 static IMG_VOID RgxEnableClock(IMG_VOID)
 {
     struct rk_context *platform;
+#if RK33_DVFS_SUPPORT
     unsigned long flags;
+#endif
 
     platform = dev_get_drvdata(&gpsPVRLDMDev->dev);
 
-    if (
-        platform->gpu_clk_node &&
-        platform->aclk_gpu_mem && platform->aclk_gpu_cfg && !platform->gpu_active)
+    if (platform->aclk_gpu_mem && platform->aclk_gpu_cfg && !platform->gpu_active)
     {
-        dvfs_clk_prepare_enable(platform->gpu_clk_node);
+        if(platform->gpu_clk_node)
+            dvfs_clk_prepare_enable(platform->gpu_clk_node);
+        else if(platform->clk_gpu)
+            clk_prepare_enable(platform->clk_gpu);
         clk_prepare_enable(platform->aclk_gpu_mem);
         clk_prepare_enable(platform->aclk_gpu_cfg);
 
 #if RK33_DVFS_SUPPORT
         rk33_dvfs_record_gpu_active(platform);
 
-        if(platform->psDeviceNode && !platform->timer_active)
+        if(platform->psDeviceNode && platform->dvfs_enabled && !platform->timer_active)
         {
+
             spin_lock_irqsave(&platform->timer_lock, flags);
             platform->timer_active = IMG_TRUE;
             spin_unlock_irqrestore(&platform->timer_lock, flags);
@@ -1713,24 +1780,25 @@ static IMG_VOID RgxEnableClock(IMG_VOID)
     {
         PVR_DPF((PVR_DBG_WARNING, "Failed to enable clock!"));
     }
+
 }
 
 static IMG_VOID RgxDisableClock(IMG_VOID)
 {
     struct rk_context *platform;
+#if RK33_DVFS_SUPPORT
     unsigned long flags;
+#endif
 
     platform = dev_get_drvdata(&gpsPVRLDMDev->dev);
 
-    if (
-        platform->gpu_clk_node &&
-        platform->aclk_gpu_mem && platform->aclk_gpu_cfg && platform->gpu_active)
+    if (platform->aclk_gpu_mem && platform->aclk_gpu_cfg && platform->gpu_active)
     {
 #if RK33_DVFS_SUPPORT
         //Force to drop freq to the lowest.
         rk33_dvfs_set_level(0);
 
-        if(platform->timer_active)
+        if(platform->dvfs_enabled && platform->timer_active)
         {
             spin_lock_irqsave(&platform->timer_lock, flags);
             platform->timer_active = IMG_FALSE;
@@ -1739,11 +1807,16 @@ static IMG_VOID RgxDisableClock(IMG_VOID)
             hrtimer_cancel(&platform->timer);
 #endif
         }
+
         rk33_dvfs_record_gpu_idle(platform);
+
 #endif
         clk_disable_unprepare(platform->aclk_gpu_cfg);
         clk_disable_unprepare(platform->aclk_gpu_mem);
-        dvfs_clk_disable_unprepare(platform->gpu_clk_node);
+        if(platform->gpu_clk_node)
+            dvfs_clk_disable_unprepare(platform->gpu_clk_node);
+        else if(platform->clk_gpu)
+            clk_disable_unprepare(platform->clk_gpu);
     }
     else
     {
@@ -1816,12 +1889,14 @@ IMG_VOID RgxResume(IMG_VOID)
 #if OPEN_GPU_PD
     RgxEnablePower();
 #endif
+
     //mdelay(2);
 
     /* set external isolation invalid */
     //writel(0, SUNXI_R_PRCM_VBASE + GPU_PWROFF_GATING);
 
     //DeAssertGpuResetSignal();
+
     RgxEnableClock();
 
     /* delay for internal power stability */
@@ -1873,6 +1948,10 @@ IMG_VOID RgxRkInit(IMG_VOID)
         return;
     }
 
+#if RK_TF_VERSION
+    rk_tf_check_version();
+#endif
+
     dev_set_drvdata(&gpsPVRLDMDev->dev, platform);
 
 #if OPEN_GPU_PD
@@ -1882,17 +1961,18 @@ IMG_VOID RgxRkInit(IMG_VOID)
     platform->psDeviceNode = NULL;
 
     spin_lock_init(&platform->cmu_pmu_lock);
+    spin_lock_init(&platform->timer_lock);
 
 #if OPEN_GPU_PD
     platform->pd_gpu_0 = devm_clk_get(&gpsPVRLDMDev->dev, "pd_gpu_0");
-    if (IS_ERR(platform->pd_gpu_0))
+    if (IS_ERR_OR_NULL(platform->pd_gpu_0))
     {
         PVR_DPF((PVR_DBG_ERROR, "RgxRkInit: Failed to find pd_gpu_0 clock source"));
         goto fail0;
     }
 
     platform->pd_gpu_1 = devm_clk_get(&gpsPVRLDMDev->dev, "pd_gpu_1");
-    if (IS_ERR(platform->pd_gpu_1))
+    if (IS_ERR_OR_NULL(platform->pd_gpu_1))
     {
         PVR_DPF((PVR_DBG_ERROR, "RgxRkInit: Failed to find pd_gpu_1 clock source"));
         goto fail1;
@@ -1900,37 +1980,46 @@ IMG_VOID RgxRkInit(IMG_VOID)
 #endif
 
     platform->aclk_gpu_mem = devm_clk_get(&gpsPVRLDMDev->dev, "aclk_gpu_mem");
-    if (IS_ERR(platform->aclk_gpu_mem))
+    if (IS_ERR_OR_NULL(platform->aclk_gpu_mem))
     {
         PVR_DPF((PVR_DBG_ERROR, "RgxRkInit: Failed to find aclk_gpu_mem clock source"));
         goto fail2;
     }
 
     platform->aclk_gpu_cfg = devm_clk_get(&gpsPVRLDMDev->dev, "aclk_gpu_cfg");
-    if (IS_ERR(platform->aclk_gpu_cfg))
+    if (IS_ERR_OR_NULL(platform->aclk_gpu_cfg))
     {
         PVR_DPF((PVR_DBG_ERROR, "RgxRkInit: Failed to find aclk_gpu_cfg clock source"));
         goto fail3;
     }
 
     platform->gpu_clk_node  = clk_get_dvfs_node("clk_gpu");
-    if (IS_ERR(platform->gpu_clk_node))
+    if (IS_ERR_OR_NULL(platform->gpu_clk_node))
     {
-        PVR_DPF((PVR_DBG_ERROR, "RgxRkInit: Failed to find gpu_clk_node clock source"));
-        goto fail4;
+        platform->dvfs_enabled = IMG_FALSE;
+        PVR_DPF((PVR_DBG_ERROR, "RgxRkInit: GPU Dvfs is disabled"));
+        platform->clk_gpu = devm_clk_get(&gpsPVRLDMDev->dev, "clk_gpu");
+        if (IS_ERR_OR_NULL(platform->clk_gpu))
+        {
+            PVR_DPF((PVR_DBG_ERROR, "RgxRkInit: Failed to find clk_gpu clock source"));
+            goto fail4;
+        }
     }
-
-    rk33_clk_set_normal_node(platform->aclk_gpu_mem, RK33_DEFAULT_CLOCK);
-    rk33_clk_set_normal_node(platform->aclk_gpu_cfg, RK33_DEFAULT_CLOCK);
-    rk33_clk_set_dvfs_node(platform->gpu_clk_node, RK33_DEFAULT_CLOCK);
+    else
+    {
+        platform->dvfs_enabled = IMG_TRUE;
+        rk33_clk_set_dvfs_node(platform->gpu_clk_node, RK33_DEFAULT_CLOCK);
+        rk33_clk_set_normal_node(platform->aclk_gpu_mem, RK33_DEFAULT_CLOCK);
+        rk33_clk_set_normal_node(platform->aclk_gpu_cfg, RK33_DEFAULT_CLOCK);
 #if RK33_DVFS_SUPPORT
-    rk33_dvfs_init();
+        rk33_dvfs_init();
 #if RK33_SYSFS_FILE_SUPPORT
-    //create sysfs file node
-    rk_create_sysfs_file(&gpsPVRLDMDev->dev);
+        //create sysfs file node
+        rk_create_sysfs_file(&gpsPVRLDMDev->dev);
 #endif
 
 #endif //end of RK33_DVFS_SUPPORT
+    }
 
     RgxResume();
 
@@ -1943,6 +2032,7 @@ fail3:
     devm_clk_put(&gpsPVRLDMDev->dev, platform->aclk_gpu_mem);
     platform->aclk_gpu_mem = NULL;
 fail2:
+
 #if OPEN_GPU_PD
     devm_clk_put(&gpsPVRLDMDev->dev, platform->pd_gpu_1);
     platform->pd_gpu_1 = NULL;
@@ -1950,7 +2040,8 @@ fail1:
     devm_clk_put(&gpsPVRLDMDev->dev, platform->pd_gpu_0);
     platform->pd_gpu_0 = NULL;
 fail0:
-#endif
+#endif //end of OPEN_GPU_PD
+
     kfree(platform);
 }
 
@@ -1960,15 +2051,52 @@ IMG_VOID RgxRkUnInit(IMG_VOID)
 
     platform = dev_get_drvdata(&gpsPVRLDMDev->dev);
 
+    RgxSuspend();
+
+    if(platform->gpu_clk_node)
+    {
+        clk_put_dvfs_node(platform->gpu_clk_node);
+        platform->gpu_clk_node = NULL;
+    }
+    else if(platform->clk_gpu)
+    {
+        devm_clk_put(&gpsPVRLDMDev->dev, platform->clk_gpu);
+        platform->clk_gpu = NULL;
+    }
+
+    if(platform->aclk_gpu_cfg)
+    {
+        devm_clk_put(&gpsPVRLDMDev->dev, platform->aclk_gpu_cfg);
+        platform->aclk_gpu_cfg = NULL;
+    }
+    if(platform->aclk_gpu_mem)
+    {
+        devm_clk_put(&gpsPVRLDMDev->dev, platform->aclk_gpu_mem);
+        platform->aclk_gpu_mem = NULL;
+    }
+#if OPEN_GPU_PD
+    if(platform->pd_gpu_1)
+    {
+        devm_clk_put(&gpsPVRLDMDev->dev, platform->pd_gpu_1);
+        platform->pd_gpu_1 = NULL;
+    }
+    if(platform->pd_gpu_0)
+    {
+        devm_clk_put(&gpsPVRLDMDev->dev, platform->pd_gpu_0);
+        platform->pd_gpu_0 = NULL;
+    }
+#endif
+
+    if(platform->dvfs_enabled)
+    {
 #if RK33_DVFS_SUPPORT
 #if RK33_SYSFS_FILE_SUPPORT
-    rk_remove_sysfs_file(&gpsPVRLDMDev->dev);
+        rk_remove_sysfs_file(&gpsPVRLDMDev->dev);
 #endif
-    rk33_dvfs_term();
+        rk33_dvfs_term();
 #endif
-
+    }
     kfree(platform);
-    RgxSuspend();
 }
 
 
index 234b5e0c9f624362668fa2096cb21d0db7ace291..b71ad46ce0c49e1bf0a2f9557a6bbe8b14d2d464 100755 (executable)
@@ -23,6 +23,8 @@
 #define USE_KTHREAD                         0
 #define USE_HRTIMER                         1
 
+#define RK_TF_VERSION                       1
+
 #define RK33_MAX_UTILIS                 4
 #define RK33_DVFS_FREQ                  50
 #define RK33_DEFAULT_CLOCK              400
@@ -92,6 +94,8 @@ struct rk_context
     IMG_INT                 cmu_pmu_status;
     /** cmd & pmu lock */
     spinlock_t              cmu_pmu_lock;
+    /*Timer*/
+    spinlock_t              timer_lock;
 
 #if OPEN_GPU_PD
     IMG_BOOL                bEnablePd;
@@ -101,13 +105,15 @@ struct rk_context
     //struct clk              *aclk_gpu;
     struct clk              *aclk_gpu_mem;
     struct clk              *aclk_gpu_cfg;
+    struct clk              *clk_gpu;
     struct dvfs_node        *gpu_clk_node;
 
     PVRSRV_DEVICE_NODE     *psDeviceNode;
-    RGXFWIF_GPU_UTIL_STATS sUtilStats;
+    RGXFWIF_GPU_UTIL_STATS  sUtilStats;
+    IMG_BOOL                gpu_active;
+    IMG_BOOL                dvfs_enabled;
 
 #if RK33_DVFS_SUPPORT
-    IMG_BOOL                gpu_active;
 #if RK33_USE_CUSTOMER_GET_GPU_UTIL
     ktime_t                 time_period_start;
 #endif
@@ -116,8 +122,6 @@ struct rk_context
     IMG_UINT32              temperature;
     IMG_UINT32              temperature_time;
 
-    /*Timer*/
-    spinlock_t              timer_lock;
 #if USE_HRTIMER
     struct hrtimer          timer;
 #endif
@@ -137,7 +141,7 @@ struct rk_context
     IMG_INT         utilisation;
     IMG_UINT32      time_busy;
     IMG_UINT32      time_idle;
-    IMG_BOOL        dvfs_enabled;
+
 #if RK33_USE_CL_COUNT_UTILS
     IMG_UINT32      abs_load[4];
 #endif