From: zxl Date: Tue, 2 Jun 2015 08:07:27 +0000 (+0800) Subject: RK3368 GPU version: Rogue L 0.17 X-Git-Tag: firefly_0821_release~4088 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=5d82dfee2f33ad21f622b864f3c8c683dc2fa5d0;p=firefly-linux-kernel-4.4.55.git RK3368 GPU version: Rogue L 0.17 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). --- diff --git a/drivers/gpu/rogue/build/linux/config/core.mk b/drivers/gpu/rogue/build/linux/config/core.mk index ddfef8546156..e2abc54b4a51 100644 --- a/drivers/gpu/rogue/build/linux/config/core.mk +++ b/drivers/gpu/rogue/build/linux/config/core.mk @@ -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, diff --git a/drivers/gpu/rogue/config_kernel.h b/drivers/gpu/rogue/config_kernel.h index 18168ff53db6..c00d1985435b 100644 --- a/drivers/gpu/rogue/config_kernel.h +++ b/drivers/gpu/rogue/config_kernel.h @@ -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 diff --git a/drivers/gpu/rogue/hwdefs/km/configs/rgxconfig_km_4.V.2.51.h b/drivers/gpu/rogue/hwdefs/km/configs/rgxconfig_km_4.V.2.51.h index 6464e705d7ae..771dd6b418ca 100644 --- a/drivers/gpu/rogue/hwdefs/km/configs/rgxconfig_km_4.V.2.51.h +++ b/drivers/gpu/rogue/hwdefs/km/configs/rgxconfig_km_4.V.2.51.h @@ -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_ */ diff --git a/drivers/gpu/rogue/hwdefs/km/rgx_cr_defs_km.h b/drivers/gpu/rogue/hwdefs/km/rgx_cr_defs_km.h index 463a5ad6b620..7ca15eceb94f 100644 --- a/drivers/gpu/rogue/hwdefs/km/rgx_cr_defs_km.h +++ b/drivers/gpu/rogue/hwdefs/km/rgx_cr_defs_km.h @@ -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 diff --git a/drivers/gpu/rogue/include/pvrversion.h b/drivers/gpu/rogue/include/pvrversion.h index 24c08f8d35f0..f763ca080be4 100755 --- a/drivers/gpu/rogue/include/pvrversion.h +++ b/drivers/gpu/rogue/include/pvrversion.h @@ -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_ */ diff --git a/drivers/gpu/rogue/kernel/drivers/staging/imgtec/adf_pdp.c b/drivers/gpu/rogue/kernel/drivers/staging/imgtec/adf_pdp.c index 8a325e14557b..1dd4f9e578be 100644 --- a/drivers/gpu/rogue/kernel/drivers/staging/imgtec/adf_pdp.c +++ b/drivers/gpu/rogue/kernel/drivers/staging/imgtec/adf_pdp.c @@ -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) { diff --git a/drivers/gpu/rogue/kernel/drivers/staging/imgtec/pvr_sync.c b/drivers/gpu/rogue/kernel/drivers/staging/imgtec/pvr_sync.c index 31cab2e359b0..e00e76fab86f 100644 --- a/drivers/gpu/rogue/kernel/drivers/staging/imgtec/pvr_sync.c +++ b/drivers/gpu/rogue/kernel/drivers/staging/imgtec/pvr_sync.c @@ -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; diff --git a/drivers/gpu/rogue/services/server/common/process_stats.c b/drivers/gpu/rogue/services/server/common/process_stats.c index d0e4b4d3fab0..79d9f15e7eb6 100755 --- a/drivers/gpu/rogue/services/server/common/process_stats.c +++ b/drivers/gpu/rogue/services/server/common/process_stats.c @@ -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: diff --git a/drivers/gpu/rogue/services/server/common/pvrsrv.c b/drivers/gpu/rogue/services/server/common/pvrsrv.c index c642bda8f87b..fdad3ef8d64d 100644 --- a/drivers/gpu/rogue/services/server/common/pvrsrv.c +++ b/drivers/gpu/rogue/services/server/common/pvrsrv.c @@ -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, diff --git a/drivers/gpu/rogue/services/server/common/resman.c b/drivers/gpu/rogue/services/server/common/resman.c index c23db6135d18..4ef15944ae82 100644 --- a/drivers/gpu/rogue/services/server/common/resman.c +++ b/drivers/gpu/rogue/services/server/common/resman.c @@ -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 { diff --git a/drivers/gpu/rogue/services/server/devices/rgx/rgxdebug.c b/drivers/gpu/rogue/services/server/devices/rgx/rgxdebug.c index b7029fd33c74..37486f9915e0 100644 --- a/drivers/gpu/rogue/services/server/devices/rgx/rgxdebug.c +++ b/drivers/gpu/rogue/services/server/devices/rgx/rgxdebug.c @@ -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 */ diff --git a/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.c b/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.c index d8a3f2c8c4f7..5a3930c9fad6 100644 --- a/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.c +++ b/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.c @@ -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) diff --git a/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.h b/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.h index 1e5bd03ab216..9e65d954a04c 100644 --- a/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.h +++ b/drivers/gpu/rogue/services/server/devices/rgx/rgxhwperf.h @@ -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); diff --git a/drivers/gpu/rogue/services/server/env/linux/mmap.c b/drivers/gpu/rogue/services/server/env/linux/mmap.c index ad16d58bd7c6..b9caeb92a285 100644 --- a/drivers/gpu/rogue/services/server/env/linux/mmap.c +++ b/drivers/gpu/rogue/services/server/env/linux/mmap.c @@ -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? } diff --git a/drivers/gpu/rogue/services/server/env/linux/module.c b/drivers/gpu/rogue/services/server/env/linux/module.c index 3e1d33e4ed8e..c190ce5c17cb 100755 --- a/drivers/gpu/rogue/services/server/env/linux/module.c +++ b/drivers/gpu/rogue/services/server/env/linux/module.c @@ -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) diff --git a/drivers/gpu/rogue/services/server/env/linux/osfunc.c b/drivers/gpu/rogue/services/server/env/linux/osfunc.c index 66455008cd9e..05265d4048af 100644 --- a/drivers/gpu/rogue/services/server/env/linux/osfunc.c +++ b/drivers/gpu/rogue/services/server/env/linux/osfunc.c @@ -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 */ diff --git a/drivers/gpu/rogue/services/server/env/linux/ossecure_export.c b/drivers/gpu/rogue/services/server/env/linux/ossecure_export.c index 1488553e6a0d..f21921597d8e 100644 --- a/drivers/gpu/rogue/services/server/env/linux/ossecure_export.c +++ b/drivers/gpu/rogue/services/server/env/linux/ossecure_export.c @@ -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; diff --git a/drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.c b/drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.c index 4299add0737f..dd8e0a4d1543 100755 --- a/drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.c +++ b/drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.c @@ -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 index 000000000000..f247875cd208 --- /dev/null +++ b/drivers/gpu/rogue/services/server/env/linux/physmem_osmem_linux.h @@ -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__ */ diff --git a/drivers/gpu/rogue/services/server/env/linux/pvr_bridge_k.c b/drivers/gpu/rogue/services/server/env/linux/pvr_bridge_k.c index 7ba442cd3762..108c6d859e4a 100644 --- a/drivers/gpu/rogue/services/server/env/linux/pvr_bridge_k.c +++ b/drivers/gpu/rogue/services/server/env/linux/pvr_bridge_k.c @@ -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 = ¶ms; -#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))) { diff --git a/drivers/gpu/rogue/services/server/env/linux/pvr_debug.c b/drivers/gpu/rogue/services/server/env/linux/pvr_debug.c index ec647497faf1..965a85144dbd 100755 --- a/drivers/gpu/rogue/services/server/env/linux/pvr_debug.c +++ b/drivers/gpu/rogue/services/server/env/linux/pvr_debug.c @@ -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; } + } diff --git a/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.c b/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.c index 044622cda23d..b37f4ad3eca0 100644 --- a/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.c +++ b/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.c @@ -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; +} diff --git a/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.h b/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.h index 7ac45888bf66..3b3f52e78cee 100644 --- a/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.h +++ b/drivers/gpu/rogue/services/server/env/linux/pvr_debugfs.h @@ -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__) */ diff --git a/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.c b/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.c index 9bb0e920c972..06adc642971d 100644 --- a/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.c +++ b/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.c @@ -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; } } diff --git a/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.h b/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.h index b681bbe64636..e4f21ee86309 100644 --- a/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.h +++ b/drivers/gpu/rogue/services/server/env/linux/pvr_gputrace.h @@ -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); diff --git a/drivers/gpu/rogue/services/server/include/osfunc.h b/drivers/gpu/rogue/services/server/include/osfunc.h index 0183527561b0..3d7e006a1b1f 100644 --- a/drivers/gpu/rogue/services/server/include/osfunc.h +++ b/drivers/gpu/rogue/services/server/include/osfunc.h @@ -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); diff --git a/drivers/gpu/rogue/services/server/include/pvrsrv.h b/drivers/gpu/rogue/services/server/include/pvrsrv.h index 1a15a72de3f4..d6c3b18bc849 100644 --- a/drivers/gpu/rogue/services/server/include/pvrsrv.h +++ b/drivers/gpu/rogue/services/server/include/pvrsrv.h @@ -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 */ diff --git a/drivers/gpu/rogue/services/server/include/resman.h b/drivers/gpu/rogue/services/server/include/resman.h index 76c41bb7bd39..4f81b865f558 100644 --- a/drivers/gpu/rogue/services/server/include/resman.h +++ b/drivers/gpu/rogue/services/server/include/resman.h @@ -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 diff --git a/drivers/gpu/rogue/services/shared/common/devicemem.c b/drivers/gpu/rogue/services/shared/common/devicemem.c index b4d49d67fd4b..7490fe9a31b3 100755 --- a/drivers/gpu/rogue/services/shared/common/devicemem.c +++ b/drivers/gpu/rogue/services/shared/common/devicemem.c @@ -1081,19 +1081,7 @@ DevmemAllocate(DEVMEM_HEAP *psHeap, PVR_ASSERT(uiSizedebugFSEntry) < 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); diff --git a/drivers/gpu/rogue/system/rk3368/rk_init.c b/drivers/gpu/rogue/system/rk3368/rk_init.c index cffac0a0080b..28d2143b0878 100755 --- a/drivers/gpu/rogue/system/rk3368/rk_init.c +++ b/drivers/gpu/rogue/system/rk3368/rk_init.c @@ -24,6 +24,66 @@ #include "power.h" #include "rk_init.h" +#include + + +#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(); } diff --git a/drivers/gpu/rogue/system/rk3368/rk_init.h b/drivers/gpu/rogue/system/rk3368/rk_init.h index 234b5e0c9f62..b71ad46ce0c4 100755 --- a/drivers/gpu/rogue/system/rk3368/rk_init.h +++ b/drivers/gpu/rogue/system/rk3368/rk_init.h @@ -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