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).
))
$(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,
#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
#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
#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_ */
#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
#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)
#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)
#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))
#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_ */
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)
{
/* 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");
}
}
}
}
-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;
}
}
-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)
{
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*),
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;
/* 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];
struct _PVRSRV_MEMORY_STATS_* psMemoryStats;
struct _PVRSRV_RI_MEMORY_STATS_* psRIMemoryStats;
+
} PVRSRV_PROCESS_STATS;
typedef struct _PVRSRV_RENDER_STATS_ {
#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,
{
PVR_ASSERT(psRenderStats != IMG_NULL);
- /* Remove the statistic from the OS... */
- OSRemoveStatisticEntry(psRenderStats->pvOSData);
-
/* Free the memory... */
OSFreeMem(psRenderStats);
} /* _DestoryRenderStat */
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 */
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 */
{
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)
{
/* 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
PVRSRV_PROCESS_STATS* psNextProcessStats = psProcessStatsToBeFreed->psNext;
psProcessStatsToBeFreed->psNext = IMG_NULL;
- _DestoryProcessStat(psProcessStatsToBeFreed);
+ _RemoveOSStatisticEntries(psProcessStatsToBeFreed);
+ _PVRSRVDecrMemStatRefCount((void*)psProcessStatsToBeFreed);
psProcessStatsToBeFreed = psNextProcessStats;
}
pvOSGlobalMemEntryRef = OSCreateStatisticEntry(pszDriverStatFilename,
IMG_NULL,
_PVRSRVGetGlobalMemStat,
+ IMG_NULL,
+ IMG_NULL,
IMG_NULL);
OSMemSet(&gsGlobalStats, 0, sizeof(gsGlobalStats));
}
/* 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... */
} /* PVRSRVStatsDestroy */
-
static void _decrease_global_stat(PVRSRV_MEM_ALLOC_TYPE eAllocType,
IMG_SIZE_T uiBytes)
{
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;
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;
}
{
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)
{
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 */
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;
}
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:
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:
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,
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);
+
/*!
******************************************************************************
}
}
+/*!
+******************************************************************************
+ @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
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
{
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) */
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;
}
}
}
+#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
+
/*!
*******************************************************************************
#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 */
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;
gpsRgxDevInfo->bFTraceGPUEventsEnabled = IMG_TRUE;
err_out:
- PVR_DPF_RETURN;
+ PVR_DPF_RETURN_RC(eError);
err_close_stream:
TLClientCloseStream(gpsRgxDevInfo->hGPUTraceTLConnection,
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;
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;
/* 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;
{
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)
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);
#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.
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?
}
{
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)
#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)
/* 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,
}
#endif /* defined(CONFIG_GENERIC_ALLOCATOR) && defined(CONFIG_X86) && (LINUX_VERSION_CODE > KERNEL_VERSION(3,0,0)) */
+ LinuxInitPagePool();
+
return PVRSRV_OK;
}
psEnvData->pvBridgeData = IMG_NULL;
OSFreeMem(psEnvData);
+
+ LinuxDeinitPagePool();
}
ENV_DATA *OSGetEnvData(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
*/ /**************************************************************************/
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 */
*/ /**************************************************************************/
void OSRemoveStatisticEntry(IMG_PVOID pvEntry)
{
- PVRDebugFSRemoveStatisticEntry(pvEntry);
+ PVRDebugFSRemoveStatisticEntry((PVR_DEBUGFS_DRIVER_STAT *)pvEntry);
} /* OSRemoveStatisticEntry */
*/ /**************************************************************************/
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 */
*/ /**************************************************************************/
void OSRemoveStatisticFolder(IMG_PVOID pvFolder)
{
- PVRDebugFSRemoveEntryDir((struct dentry *)pvFolder);
+ PVRDebugFSRemoveEntryDir((PVR_DEBUGFS_DIR_DATA *)pvFolder);
} /* OSRemoveStatisticFolder */
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));
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;
/* ourselves */
#include "physmem_osmem.h"
+#include "physmem_osmem_linux.h"
#if defined(PVRSRV_ENABLE_PROCESS_STATS)
#include "process_stats.h"
*/
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 *
***********************************/
/* 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;
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
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)
{
#if defined(PHYSMEM_SUPPORTS_SHRINKER)
unregister_shrinker(&g_sShrinker);
#endif
- _PagePoolUnlock();
}
static void EnableOOMKiller(void)
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
{
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;
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
&ppsPageArray[uiPageIndex],
&bPageFromPool);
-#if defined(CONFIG_X86)
if (!bPageFromPool)
{
apsUnsetPages[uiUnsetPagesIndex] = ppsPageArray[uiPageIndex];
uiUnsetPagesIndex++;
}
-#endif
if (eError != PVRSRV_OK)
{
#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)
/*
}
}
-
- 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;
*/
e_freed_pages:
-#if defined (CONFIG_X86)
OSFreeMem(apsUnsetPages);
e_exit:
-#endif
PVR_ASSERT(eError != PVRSRV_OK);
return eError;
}
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;
#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)
{
}
#endif
- PVR_ASSERT(psPageArrayData->bHasOSPages);
- g_ui32LiveAllocs--;
-
ppsPageArray = psPageArrayData->pagearray;
uiNumPages = psPageArrayData->uiNumPages;
_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)
{
}
}
- 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;
}
/* 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;
}
if (psOSPageArrayData->bOnDemand)
{
/* Free Memory for deferred allocation */
- eError = _FreeOSPages(psOSPageArrayData);
+ eError = _FreeOSPages(psOSPageArrayData, IMG_FALSE);
if (eError != PVRSRV_OK)
{
return eError;
errorOnCreate:
if (!bOnDemand)
{
- eError2 = _FreeOSPages(psPrivData);
+ eError2 = _FreeOSPages(psPrivData, IMG_FALSE);
PVR_ASSERT(eError2 == PVRSRV_OK);
}
--- /dev/null
+/*************************************************************************/ /*!
+@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__ */
#endif
#if defined(DEBUG_BRIDGE_KM)
-static struct dentry *gpsPVRDebugFSBridgeStatsEntry = NULL;
+static PVR_DEBUGFS_ENTRY_DATA *gpsPVRDebugFSBridgeStatsEntry = NULL;
static struct seq_operations gsBridgeStatsReadOps;
#endif
&gsBridgeStatsReadOps,
NULL,
&g_BridgeDispatchTable[0],
- &gpsPVRDebugFSBridgeStatsEntry);
+ &gpsPVRDebugFSBridgeStatsEntry);
if (iResult != 0)
{
return PVRSRV_ERROR_OUT_OF_MEMORY;
LinuxBridgeDeInit(void)
{
#if defined(DEBUG_BRIDGE_KM)
- PVRDebugFSRemoveEntry(gpsPVRDebugFSBridgeStatsEntry);
- gpsPVRDebugFSBridgeStatsEntry = NULL;
+ PVRDebugFSRemoveEntry(gpsPVRDebugFSBridgeStatsEntry);
+ gpsPVRDebugFSBridgeStatsEntry = NULL;
#endif
}
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);
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)))
{
}
#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)
NULL,
psPVRSRVData,
&gpsVersionDebugFSEntry);
+
if (iResult != 0)
{
return iResult;
PVRDebugFSRemoveEntry(gpsVersionDebugFSEntry);
gpsVersionDebugFSEntry = NULL;
}
+
}
static struct dentry *gpsPVRDebugFSEntryDir = NULL;
+/* Lock used when adjusting refCounts and deleting entries */
+static struct mutex gDebugFSLock;
/*************************************************************************/ /*!
Statistic entry read functions
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;
}
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;
}
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;
}
.read = seq_read,
.write = _DebugFSFileWrite,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = _DebugFSFileClose,
};
{
PVR_ASSERT(gpsPVRDebugFSEntryDir == NULL);
+ mutex_init(&gDebugFSLock);
+
gpsPVRDebugFSEntryDir = debugfs_create_dir(PVR_DEBUGFS_DIR_NAME, NULL);
if (gpsPVRDebugFSEntryDir == NULL)
{
debugfs_remove(gpsPVRDebugFSEntryDir);
gpsPVRDebugFSEntryDir = NULL;
+ mutex_destroy(&gDebugFSLock);
}
/*************************************************************************/ /*!
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;
}
@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
@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;
{
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;
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))
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;
}
/*************************************************************************/ /*!
@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;
+}
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__) */
/* DebugFS entry for the feature's on/off file */
-static struct dentry* gpsPVRDebugFSGpuTracingOnEntry = NULL;
+static PVR_DEBUGFS_ENTRY_DATA *gpsPVRDebugFSGpuTracingOnEntry = NULL;
/*
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;
}
}
&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;
}
}
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);
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);
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 */
#endif
#include "servicesext.h"
+#include "dllist.h"
/******************************************************************************
* resman definitions
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
*****************************************************************************/
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
PVR_ASSERT(uiSize<IMG_UINT32_MAX);
#endif
-#if defined(CONFIG_ARM64) || defined(__arm64__) || defined(__aarch64__)
- {
- IMG_UINT32 i;
- IMG_BYTE * pbyPtr;
-
- pbyPtr = (IMG_BYTE*) pvAddr;
- for (i = 0; i < uiSize; i++)
- *pbyPtr++ = 0;
- }
-
-#else
OSMemSet(pvAddr, 0x0, (IMG_SIZE_T) uiSize);
-#endif
DevmemReleaseCpuVirtAddr(psMemDesc);
IMG_UINT32 ui32ReadEntry;
IMG_BOOL bEnteredResetMode;
- struct dentry *debugFSEntry;
+ PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
PFN_APOLLO_FLASH_INIT pfnFlashInit;
PFN_APOLLO_FLASH_WRITE pfnFlashWrite;
PFN_APOLLO_FLASH_GET_STATUS pfnFlashGetStatus;
&gsFlasherReadOps,
(PVRSRV_ENTRY_WRITE_FUNC *)ApolloFlashWrite,
(IMG_VOID *)psApolloFlashData,
- &psApolloFlashData->debugFSEntry) < 0)
+ &psApolloFlashData->psDebugFSEntry) < 0)
{
OSFreeMem(psApolloFlashData);
if (psFlashData != IMG_NULL)
{
- if (psFlashData->debugFSEntry != NULL)
+ if (psFlashData->psDebugFSEntry != NULL)
{
- PVRDebugFSRemoveEntry(psFlashData->debugFSEntry);
+ PVRDebugFSRemoveEntry(psFlashData->psDebugFSEntry);
}
OSFreeMem(hFlasher);
#include "power.h"
#include "rk_init.h"
+#include <asm/compiler.h>
+
+
+#if RK_TF_VERSION
+#define PSCI_RKSIP_TF_VERSION (0x82000001)
+
+
+static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
+ u64 arg2)
+{
+ asm volatile(
+ __asmeq("%0", "x0")
+ __asmeq("%1", "x1")
+ __asmeq("%2", "x2")
+ __asmeq("%3", "x3")
+ "smc #0\n"
+ : "+r" (function_id)
+ : "r" (arg0), "r" (arg1), "r" (arg2));
+
+
+ return function_id;
+}
+
+static int (*invoke_psci_fn)(u64, u64 , u64, u64) = __invoke_psci_fn_smc;
+
+
+static int rk_tf_get_version(void)
+{
+ int ver_num;
+ ver_num = invoke_psci_fn(PSCI_RKSIP_TF_VERSION, 0, 0, 0);
+
+ return ver_num;
+}
+
+static int rk_tf_check_version(void)
+{
+ int version=0;
+ int high_16=0;
+ int low_16=0;
+ IMG_PINT pNULL=NULL;
+
+ version = rk_tf_get_version();
+ high_16 = (version >> 16) & ~(0xFFFF << 16);
+ low_16 = (version & ~(0xFFFF << 16));
+
+ printk("raw version=0x%x,rk_tf_version=%x.%x\n",version,high_16,low_16);
+
+ if((version != 0xFFFFFFFF) && (high_16 >= 1) && (low_16 >= 3))
+ {
+ return 0;
+ }
+ else
+ {
+ printk("Error:%s-line:%d This version cann't support rk3328\n",__func__,__LINE__);
+ *pNULL=0; //crash system
+ return -1;
+ }
+}
+
+#endif
extern struct platform_device *gpsPVRLDMDev;
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");
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;
}
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;
#endif //RK33_DVFS_FREQ_LIMIT
#endif //RK33_SYSFS_FILE_SUPPORT
- //dvfs timer
- spin_lock_init(&platform->timer_lock);
#if USE_HRTIMER
{
//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);
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;
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);
{
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;
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
{
#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 */
return;
}
+#if RK_TF_VERSION
+ rk_tf_check_version();
+#endif
+
dev_set_drvdata(&gpsPVRLDMDev->dev, platform);
#if OPEN_GPU_PD
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;
#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();
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;
devm_clk_put(&gpsPVRLDMDev->dev, platform->pd_gpu_0);
platform->pd_gpu_0 = NULL;
fail0:
-#endif
+#endif //end of OPEN_GPU_PD
+
kfree(platform);
}
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();
}
#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
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;
//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
IMG_UINT32 temperature;
IMG_UINT32 temperature_time;
- /*Timer*/
- spinlock_t timer_lock;
#if USE_HRTIMER
struct hrtimer timer;
#endif
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