summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Hamilton <jonathan.hamilton@imgtec.com>2016-10-21 08:23:12 -0700
committerThierry Strudel <tstrudel@google.com>2016-10-24 17:46:14 +0000
commitba519d2df3205a2d43ae0bcd3bfc489caf97ce71 (patch)
treed05357cd5e80a8b27688bf170e35e79d0be0d7b6
parent8b19ac91b1ce42dba0e8ea64423ecad9f9c929ed (diff)
downloadx86_64-ba519d2df3205a2d43ae0bcd3bfc489caf97ce71.tar.gz
gpu: Update to DDK 1.6@4278818android-7.1.1_r0.7
Fixes a possible race when reading debugfs /d/pvr/pid/<pid>/process_stats that could cause a use-after-free and crash Fixes a possible use-after-free if kthread_stop() fails when unloading the driver Bug: 30938609 Bug: 31952096 Signed-off-by: Jonathan Hamilton <jonathan.hamilton@imgtec.com> Change-Id: I1bba121f90ebc400f6a19781714e71d8d238c2f8
-rw-r--r--drivers/staging/imgtec/adf_common.c88
-rw-r--r--drivers/staging/imgtec/pvr_sync.c6
-rw-r--r--drivers/staging/imgtec/pvrversion.h6
-rw-r--r--drivers/staging/imgtec/rogue/cache_external.h6
-rw-r--r--drivers/staging/imgtec/rogue/cache_generic.c2
-rw-r--r--drivers/staging/imgtec/rogue/osfunc.c7
-rw-r--r--drivers/staging/imgtec/rogue/pvr_bridge_k.c2
-rw-r--r--drivers/staging/imgtec/rogue/pvr_debug.c10
-rw-r--r--drivers/staging/imgtec/rogue/pvr_debugfs.c59
-rw-r--r--drivers/staging/imgtec/rogue/pvr_debugfs.h5
-rw-r--r--drivers/staging/imgtec/rogue/pvr_gputrace.c3
-rw-r--r--drivers/staging/imgtec/rogue/pvr_hwperf.c4
-rw-r--r--drivers/staging/imgtec/rogue/pvrsrv.c26
-rw-r--r--drivers/staging/imgtec/rogue/pvrsrv.h7
14 files changed, 156 insertions, 75 deletions
diff --git a/drivers/staging/imgtec/adf_common.c b/drivers/staging/imgtec/adf_common.c
index a32f8ff4e7c9..1f1f28f616d0 100644
--- a/drivers/staging/imgtec/adf_common.c
+++ b/drivers/staging/imgtec/adf_common.c
@@ -60,45 +60,62 @@ static long validate(struct adf_device *dev,
struct adf_validate_config_ext __user *arg)
{
struct adf_interface **intfs = NULL;
+ struct adf_validate_config_ext data;
struct adf_buffer *bufs = NULL;
struct adf_post post_cfg;
+ void *post_ext = NULL;
u32 post_ext_size;
void *driver_state;
int err = 0;
size_t i, j;
- if (arg->n_interfaces > ADF_MAX_INTERFACES) {
+ if (copy_from_user(&data, arg, sizeof(data))) {
+ err = -EFAULT;
+ goto err_out;
+ }
+
+ if (data.n_interfaces > ADF_MAX_INTERFACES) {
err = -EINVAL;
goto err_out;
}
- if (arg->n_bufs > ADF_MAX_BUFFERS) {
+ if (data.n_bufs > ADF_MAX_BUFFERS) {
err = -EINVAL;
goto err_out;
}
post_ext_size = sizeof(struct adf_post_ext) +
- arg->n_bufs * sizeof(struct adf_buffer_config_ext);
+ data.n_bufs * sizeof(struct adf_buffer_config_ext);
+
+ if (!access_ok(VERIFY_READ, data.bufs,
+ sizeof(*data.bufs) * data.n_bufs)) {
+ err = -EFAULT;
+ goto err_out;
+ }
+
+ post_ext = kmalloc(post_ext_size, GFP_KERNEL);
+ if (!post_ext) {
+ err = -ENOMEM;
+ goto err_out;
+ }
- if (!access_ok(VERIFY_READ, arg->bufs,
- sizeof(struct adf_buffer_config) * arg->n_bufs)) {
+ if (!access_ok(VERIFY_READ, data.post_ext, post_ext_size)) {
err = -EFAULT;
goto err_out;
}
- if (!access_ok(VERIFY_READ, arg->post_ext,
- post_ext_size)) {
+ if (copy_from_user(post_ext, data.post_ext, post_ext_size)) {
err = -EFAULT;
goto err_out;
}
- if (arg->n_interfaces) {
- if (!access_ok(VERIFY_READ, arg->interfaces,
- sizeof(*arg->interfaces) * arg->n_interfaces)) {
+ if (data.n_interfaces) {
+ if (!access_ok(VERIFY_READ, data.interfaces,
+ sizeof(*data.interfaces) *data.n_interfaces)) {
err = -EFAULT;
goto err_out;
}
- intfs = kmalloc_array(arg->n_interfaces, sizeof(intfs[0]),
+ intfs = kmalloc_array(data.n_interfaces, sizeof(intfs[0]),
GFP_KERNEL);
if (!intfs) {
err = -ENOMEM;
@@ -106,62 +123,72 @@ static long validate(struct adf_device *dev,
}
}
- for (i = 0; i < arg->n_interfaces; i++) {
- intfs[i] = idr_find(&dev->interfaces, arg->interfaces[i]);
+ for (i = 0; i < data.n_interfaces; i++) {
+ u32 intf_id;
+ if (get_user(intf_id, &data.interfaces[i])) {
+ err = -EFAULT;
+ goto err_out;
+ }
+ intfs[i] = idr_find(&dev->interfaces, intf_id);
if (!intfs[i]) {
err = -EINVAL;
goto err_out;
}
}
- if (arg->n_bufs) {
- bufs = kcalloc(arg->n_bufs, sizeof(bufs[0]), GFP_KERNEL);
+ if (data.n_bufs) {
+ bufs = kcalloc(data.n_bufs, sizeof(bufs[0]), GFP_KERNEL);
if (!bufs) {
err = -ENOMEM;
goto err_out;
}
}
- for (i = 0; i < arg->n_bufs; i++) {
- struct adf_buffer_config *config = &arg->bufs[i];
+ for (i = 0; i < data.n_bufs; i++) {
+ struct adf_buffer_config config;
+
+ if (copy_from_user(&config, &data.bufs[i], sizeof(config))) {
+ err = -EFAULT;
+ goto err_out;
+ }
memset(&bufs[i], 0, sizeof(bufs[i]));
- if (config->n_planes > ADF_MAX_PLANES) {
+ if (config.n_planes > ADF_MAX_PLANES) {
err = -EINVAL;
goto err_import;
}
bufs[i].overlay_engine = idr_find(&dev->overlay_engines,
- config->overlay_engine);
+ config.overlay_engine);
if (!bufs[i].overlay_engine) {
err = -ENOENT;
goto err_import;
}
- bufs[i].w = config->w;
- bufs[i].h = config->h;
- bufs[i].format = config->format;
+ bufs[i].w = config.w;
+ bufs[i].h = config.h;
+ bufs[i].format = config.format;
- for (j = 0; j < config->n_planes; j++) {
- bufs[i].dma_bufs[j] = dma_buf_get(config->fd[j]);
+ for (j = 0; j < config.n_planes; j++) {
+ bufs[i].dma_bufs[j] = dma_buf_get(config.fd[j]);
if (IS_ERR_OR_NULL(bufs[i].dma_bufs[j])) {
err = PTR_ERR(bufs[i].dma_bufs[j]);
bufs[i].dma_bufs[j] = NULL;
goto err_import;
}
- bufs[i].offset[j] = config->offset[j];
- bufs[i].pitch[j] = config->pitch[j];
+ bufs[i].offset[j] = config.offset[j];
+ bufs[i].pitch[j] = config.pitch[j];
}
- bufs[i].n_planes = config->n_planes;
+ bufs[i].n_planes = config.n_planes;
bufs[i].acquire_fence = NULL;
}
/* Fake up a post configuration to validate */
post_cfg.custom_data_size = post_ext_size;
- post_cfg.custom_data = arg->post_ext;
- post_cfg.n_bufs = arg->n_bufs;
+ post_cfg.custom_data = post_ext;
+ post_cfg.n_bufs = data.n_bufs;
post_cfg.bufs = bufs;
/* Mapping dma bufs is too expensive for validate, and we don't
@@ -180,11 +207,12 @@ static long validate(struct adf_device *dev,
dev->ops->state_free(dev, driver_state);
err_import:
- for (i = 0; i < arg->n_bufs; i++)
+ for (i = 0; i < data.n_bufs; i++)
for (j = 0; j < ARRAY_SIZE(bufs[i].dma_bufs); j++)
if (bufs[i].dma_bufs[j])
dma_buf_put(bufs[i].dma_bufs[j]);
err_out:
+ kfree(post_ext);
kfree(intfs);
kfree(bufs);
return err;
diff --git a/drivers/staging/imgtec/pvr_sync.c b/drivers/staging/imgtec/pvr_sync.c
index 11d9424092e5..e78af6aebdb0 100644
--- a/drivers/staging/imgtec/pvr_sync.c
+++ b/drivers/staging/imgtec/pvr_sync.c
@@ -98,9 +98,11 @@ static inline int sync_pt_get_status(struct sync_pt *pt)
}
#define for_each_sync_pt(s, f, c) \
- for ((c) = 0, (s) = (struct sync_pt *)(f)->cbs[0].sync_pt; \
+ for ((c) = 0, (s) = (f)->num_fences == 0 ? \
+ NULL : (struct sync_pt *)(f)->cbs[0].sync_pt; \
(c) < (f)->num_fences; \
- (c)++, (s) = (struct sync_pt *)(f)->cbs[c].sync_pt)
+ (c)++, (s) = (c) < (f)->num_fences ? \
+ (struct sync_pt *)(f)->cbs[c].sync_pt : NULL)
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)) */
diff --git a/drivers/staging/imgtec/pvrversion.h b/drivers/staging/imgtec/pvrversion.h
index c0ef79fe6b4b..d4da95449f1a 100644
--- a/drivers/staging/imgtec/pvrversion.h
+++ b/drivers/staging/imgtec/pvrversion.h
@@ -53,7 +53,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define PVRVERSION_FAMILY "rogueddk"
#define PVRVERSION_BRANCHNAME "1.6"
-#define PVRVERSION_BUILD 4250457
+#define PVRVERSION_BUILD 4278818
#define PVRVERSION_BSCONTROL "Rogue_DDK_Android"
#define PVRVERSION_STRING "Rogue_DDK_Android rogueddk 1.6@" PVR_STR2(PVRVERSION_BUILD)
@@ -61,8 +61,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define COPYRIGHT_TXT "Copyright (c) Imagination Technologies Ltd. All Rights Reserved."
-#define PVRVERSION_BUILD_HI 425
-#define PVRVERSION_BUILD_LO 457
+#define PVRVERSION_BUILD_HI 427
+#define PVRVERSION_BUILD_LO 8818
#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))
diff --git a/drivers/staging/imgtec/rogue/cache_external.h b/drivers/staging/imgtec/rogue/cache_external.h
index ff022f89e616..134845bdcc1a 100644
--- a/drivers/staging/imgtec/rogue/cache_external.h
+++ b/drivers/staging/imgtec/rogue/cache_external.h
@@ -55,9 +55,9 @@ typedef IMG_UINT32 PVRSRV_CACHE_OP;
typedef IMG_UINT32 PVRSRV_CACHE_OP_ADDR_TYPE;
-#define PVRSRV_CACHE_OP_ADDR_TYPE_VIRTUAL 0x1 /*!< Operation require virtual address only */
-#define PVRSRV_CACHE_OP_ADDR_TYPE_PHYSICAL 0x2 /*!< Operation require physical address only */
-#define PVRSRV_CACHE_OP_ADDR_TYPE_BOTH 0x3 /*!< Operation require both virtual & physical addresses */
+#define PVRSRV_CACHE_OP_ADDR_TYPE_VIRTUAL 0x1 /*!< Operation requires virtual address only */
+#define PVRSRV_CACHE_OP_ADDR_TYPE_PHYSICAL 0x2 /*!< Operation requires physical address only */
+#define PVRSRV_CACHE_OP_ADDR_TYPE_BOTH 0x3 /*!< Operation requires both virtual & physical addresses */
/*
If we get multiple cache operations before the operation which will
diff --git a/drivers/staging/imgtec/rogue/cache_generic.c b/drivers/staging/imgtec/rogue/cache_generic.c
index 3c8dd968500c..38eff4a9403f 100644
--- a/drivers/staging/imgtec/rogue/cache_generic.c
+++ b/drivers/staging/imgtec/rogue/cache_generic.c
@@ -242,7 +242,7 @@ PVRSRV_ERROR CacheOpQueue(PMR *psPMR,
/* We always retrieve PMR data in bulk, up-front if number of pages is within
PMR_MAX_TRANSLATION_STACK_ALLOC limits else we check to ensure that a
- dynamic buffer as been allocated to satisfy requests outside limits */
+ dynamic buffer has been allocated to satisfy requests outside limits */
if (ui32NumOfPages <= PMR_MAX_TRANSLATION_STACK_ALLOC || pbValid != abValid)
{
if (uiCacheOpAddrType != PVRSRV_CACHE_OP_ADDR_TYPE_VIRTUAL)
diff --git a/drivers/staging/imgtec/rogue/osfunc.c b/drivers/staging/imgtec/rogue/osfunc.c
index 94188d18754c..76602ef0cee5 100644
--- a/drivers/staging/imgtec/rogue/osfunc.c
+++ b/drivers/staging/imgtec/rogue/osfunc.c
@@ -1124,7 +1124,12 @@ PVRSRV_ERROR OSThreadDestroy(IMG_HANDLE hThread)
/* Let the thread know we are ready for it to end and wait for it. */
ret = kthread_stop(psOSThreadData->kthread);
- PVR_ASSERT(ret == 0);
+ if (0 != ret)
+ {
+ PVR_DPF((PVR_DBG_WARNING, "kthread_stop failed(%d)", ret));
+ return PVRSRV_ERROR_RETRY;
+ }
+
OSFreeMem(psOSThreadData);
return PVRSRV_OK;
diff --git a/drivers/staging/imgtec/rogue/pvr_bridge_k.c b/drivers/staging/imgtec/rogue/pvr_bridge_k.c
index acc4fb49aa92..b8964b94f26b 100644
--- a/drivers/staging/imgtec/rogue/pvr_bridge_k.c
+++ b/drivers/staging/imgtec/rogue/pvr_bridge_k.c
@@ -195,6 +195,8 @@ LinuxBridgeInit(void)
NULL,
&gsBridgeStatsReadOps,
NULL,
+ NULL,
+ NULL,
&g_BridgeDispatchTable[0],
&gpsPVRDebugFSBridgeStatsEntry);
if (iResult != 0)
diff --git a/drivers/staging/imgtec/rogue/pvr_debug.c b/drivers/staging/imgtec/rogue/pvr_debug.c
index 85de04d65113..003c37baf737 100644
--- a/drivers/staging/imgtec/rogue/pvr_debug.c
+++ b/drivers/staging/imgtec/rogue/pvr_debug.c
@@ -1200,6 +1200,8 @@ int PVRDebugCreateDebugFSEntries(void)
NULL,
&gsDebugVersionReadOps,
NULL,
+ NULL,
+ NULL,
psPVRSRVData,
&gpsVersionDebugFSEntry);
if (iResult != 0)
@@ -1211,6 +1213,8 @@ int PVRDebugCreateDebugFSEntries(void)
NULL,
&gsDebugStatusReadOps,
(PVRSRV_ENTRY_WRITE_FUNC *)DebugStatusSet,
+ NULL,
+ NULL,
psPVRSRVData,
&gpsStatusDebugFSEntry);
if (iResult != 0)
@@ -1222,6 +1226,8 @@ int PVRDebugCreateDebugFSEntries(void)
NULL,
&gsDumpDebugReadOps,
NULL,
+ NULL,
+ NULL,
psPVRSRVData,
&gpsDumpDebugDebugFSEntry);
if (iResult != 0)
@@ -1233,6 +1239,8 @@ int PVRDebugCreateDebugFSEntries(void)
NULL,
&gsFWTraceReadOps,
NULL,
+ NULL,
+ NULL,
psPVRSRVData,
&gpsFWTraceDebugFSEntry);
if (iResult != 0)
@@ -1245,6 +1253,8 @@ int PVRDebugCreateDebugFSEntries(void)
NULL,
&gsDebugLevelReadOps,
(PVRSRV_ENTRY_WRITE_FUNC *)DebugLevelSet,
+ NULL,
+ NULL,
&gPVRDebugLevel,
&gpsDebugLevelDebugFSEntry);
if (iResult != 0)
diff --git a/drivers/staging/imgtec/rogue/pvr_debugfs.c b/drivers/staging/imgtec/rogue/pvr_debugfs.c
index fd41407a59e4..cba6d6c0997e 100644
--- a/drivers/staging/imgtec/rogue/pvr_debugfs.c
+++ b/drivers/staging/imgtec/rogue/pvr_debugfs.c
@@ -98,6 +98,8 @@ typedef struct _PVR_DEBUGFS_PRIV_DATA_
struct seq_operations *psReadOps;
PVRSRV_ENTRY_WRITE_FUNC *pfnWrite;
void *pvData;
+ PVRSRV_INC_FSENTRY_PVDATA_REFCNT_FN *pfIncPvDataRefCnt;
+ PVRSRV_DEC_FSENTRY_PVDATA_REFCNT_FN *pfDecPvDataRefCnt;
IMG_BOOL bValid;
PVR_DEBUGFS_ENTRY_DATA *psDebugFSEntry;
} PVR_DEBUGFS_PRIV_DATA;
@@ -127,18 +129,13 @@ static void *_DebugFSStatisticSeqStart(struct seq_file *psSeqFile, loff_t *puiPo
if (psStatData)
{
- if (psStatData->pvData)
- {
- /* take reference on psStatData (for duration of stat iteration) */
- if (!_RefStatEntry((void*)psStatData))
- {
- PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called for '%s' but failed to take ref on stat entry, returning -EIO(%d)", __FUNCTION__, psStatData->pvDebugFSEntry->psEntry->d_iname, -EIO));
- return NULL;
- }
- }
- else
+ /* take reference on psStatData (for duration of stat iteration) */
+ if (!_RefStatEntry(psStatData))
{
- /* NB This is valid if the stat has no structure associated with it (eg. driver_stats, which prints totals stored in a number of global vars) */
+ PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called for '%s' but failed"
+ " to take ref on stat entry, returning -EIO(%d)", __func__,
+ psStatData->pvDebugFSEntry->psEntry->d_iname, -EIO));
+ return NULL;
}
if (*puiPosition == 0)
@@ -162,24 +159,11 @@ static void _DebugFSStatisticSeqStop(struct seq_file *psSeqFile, void *pvData)
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))
+ if (psStatData->ui32RefCount > 0)
{
/* drop reference on psStatData (held for duration of stat iteration) */
_UnrefAndMaybeDestroyStatEntry((void*)psStatData);
}
- else
- {
- if (psStatData->ui32RefCount > 0)
- {
- /* psStatData->pvData is NULL */
- /* NB This is valid if the stat has no structure associated with it (eg. driver_stats, which prints totals stored in a number of global vars) */
- }
- if (psStatData->pvData)
- {
- /* psStatData->ui32RefCount is zero */
- PVR_DPF((PVR_DEBUGFS_PVR_DPF_LEVEL, "%s: Called when psStatData->ui32RefCount is %d", __FUNCTION__, psStatData->ui32RefCount));
- }
- }
}
else
{
@@ -271,12 +255,16 @@ static int _DebugFSFileOpen(struct inode *psINode, struct file *psFile)
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
- */
+ * fail to open the seq file or when we close it
+ */
if (psDebugFSEntry)
{
bRefRet = _RefDebugFSEntryNoLock(psDebugFSEntry);
mutex_unlock(&gDebugFSLock);
+ if (psPrivData->pfIncPvDataRefCnt)
+ {
+ psPrivData->pfIncPvDataRefCnt(psPrivData->pvData);
+ }
if (bRefRet)
{
iResult = seq_open(psFile, psPrivData->psReadOps);
@@ -288,6 +276,10 @@ static int _DebugFSFileOpen(struct inode *psINode, struct file *psFile)
}
else
{
+ if (psPrivData->pfDecPvDataRefCnt)
+ {
+ psPrivData->pfDecPvDataRefCnt(psPrivData->pvData);
+ }
/* Drop ref if we failed to open seq file */
_UnrefAndMaybeDestroyDebugFSEntry(&psPrivData->psDebugFSEntry);
PVR_DPF((PVR_DBG_ERROR, "%s: Failed to seq_open psFile, returning %d", __FUNCTION__, iResult));
@@ -327,6 +319,10 @@ static int _DebugFSFileClose(struct inode *psINode, struct file *psFile)
{
_UnrefAndMaybeDestroyDebugFSEntry(&psPrivData->psDebugFSEntry);
}
+ if (psPrivData->pfDecPvDataRefCnt)
+ {
+ psPrivData->pfDecPvDataRefCnt(psPrivData->pvData);
+ }
return iResult;
}
@@ -510,6 +506,8 @@ int PVRDebugFSCreateEntry(const char *pszName,
PVR_DEBUGFS_DIR_DATA *psParentDir,
struct seq_operations *psReadOps,
PVRSRV_ENTRY_WRITE_FUNC *pfnWrite,
+ PVRSRV_INC_FSENTRY_PVDATA_REFCNT_FN *pfnIncPvDataRefCnt,
+ PVRSRV_DEC_FSENTRY_PVDATA_REFCNT_FN *pfnDecPvDataRefCnt,
void *pvData,
PVR_DEBUGFS_ENTRY_DATA **ppsNewEntry)
{
@@ -519,6 +517,8 @@ int PVRDebugFSCreateEntry(const char *pszName,
umode_t uiMode;
PVR_ASSERT(gpsPVRDebugFSEntryDir != NULL);
+ PVR_ASSERT(!((pfnIncPvDataRefCnt != NULL && pfnDecPvDataRefCnt == NULL) ||
+ (pfnIncPvDataRefCnt == NULL && pfnDecPvDataRefCnt != NULL)));
psPrivData = OSAllocMemNoStats(sizeof(*psPrivData));
if (psPrivData == NULL)
@@ -535,6 +535,8 @@ int PVRDebugFSCreateEntry(const char *pszName,
psPrivData->psReadOps = psReadOps;
psPrivData->pfnWrite = pfnWrite;
psPrivData->pvData = (void*)pvData;
+ psPrivData->pfIncPvDataRefCnt = pfnIncPvDataRefCnt;
+ psPrivData->pfDecPvDataRefCnt = pfnDecPvDataRefCnt;
psPrivData->bValid = IMG_TRUE;
/* Store ptr to debugFSEntry in psPrivData, so a ref can be taken on it
* when the client opens a file */
@@ -660,6 +662,8 @@ PVR_DEBUGFS_DRIVER_STAT *PVRDebugFSCreateStatisticEntry(const char *pszName,
psDir,
&gsDebugFSStatisticReadOps,
NULL,
+ (PVRSRV_INC_FSENTRY_PVDATA_REFCNT_FN *) _RefStatEntry,
+ (PVRSRV_DEC_FSENTRY_PVDATA_REFCNT_FN *) _UnrefAndMaybeDestroyStatEntry,
psStatData,
&psDebugFSEntry);
if (iResult != 0)
@@ -690,6 +694,7 @@ PVR_DEBUGFS_DRIVER_STAT *PVRDebugFSCreateStatisticEntry(const char *pszName,
*/ /**************************************************************************/
void PVRDebugFSRemoveStatisticEntry(PVR_DEBUGFS_DRIVER_STAT *psStatEntry)
{
+ PVR_ASSERT(psStatEntry != NULL);
/* drop reference on pvStatEntry*/
_UnrefAndMaybeDestroyStatEntry(psStatEntry);
}
diff --git a/drivers/staging/imgtec/rogue/pvr_debugfs.h b/drivers/staging/imgtec/rogue/pvr_debugfs.h
index 8151ebdcb3b9..90cf9e2fd8c5 100644
--- a/drivers/staging/imgtec/rogue/pvr_debugfs.h
+++ b/drivers/staging/imgtec/rogue/pvr_debugfs.h
@@ -58,6 +58,9 @@ typedef ssize_t (PVRSRV_ENTRY_WRITE_FUNC)(const char __user *pszBuffer,
typedef IMG_UINT32 (PVRSRV_INC_STAT_MEM_REFCOUNT_FUNC)(void *pvStatPtr);
typedef IMG_UINT32 (PVRSRV_DEC_STAT_MEM_REFCOUNT_FUNC)(void *pvStatPtr);
+typedef IMG_UINT32 (PVRSRV_INC_FSENTRY_PVDATA_REFCNT_FN)(void *pvData);
+typedef IMG_UINT32 (PVRSRV_DEC_FSENTRY_PVDATA_REFCNT_FN)(void *pvData);
+
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;
@@ -75,6 +78,8 @@ int PVRDebugFSCreateEntry(const char *pszName,
PVR_DEBUGFS_DIR_DATA *psParentDir,
struct seq_operations *psReadOps,
PVRSRV_ENTRY_WRITE_FUNC *pfnWrite,
+ PVRSRV_INC_FSENTRY_PVDATA_REFCNT_FN *pfnIncPvDataRefCnt,
+ PVRSRV_DEC_FSENTRY_PVDATA_REFCNT_FN *pfnDecPvDataRefCnt,
void *pvData,
PVR_DEBUGFS_ENTRY_DATA **ppsNewEntry);
diff --git a/drivers/staging/imgtec/rogue/pvr_gputrace.c b/drivers/staging/imgtec/rogue/pvr_gputrace.c
index 1dccb7a7ccc5..01bd8358d422 100644
--- a/drivers/staging/imgtec/rogue/pvr_gputrace.c
+++ b/drivers/staging/imgtec/rogue/pvr_gputrace.c
@@ -277,7 +277,8 @@ PVRSRV_ERROR PVRGpuTraceInit(PVRSRV_DEVICE_NODE *psDeviceNode)
eError = PVRDebugFSCreateEntry("gpu_tracing_on", NULL, &gsGpuTracingReadOps,
(PVRSRV_ENTRY_WRITE_FUNC *)GpuTracingSet,
- NULL, &gpsPVRDebugFSGpuTracingOnEntry);
+ NULL, NULL, NULL,
+ &gpsPVRDebugFSGpuTracingOnEntry);
if (eError != PVRSRV_OK)
{
RGXHWPerfFTraceGPUDeInit();
diff --git a/drivers/staging/imgtec/rogue/pvr_hwperf.c b/drivers/staging/imgtec/rogue/pvr_hwperf.c
index 1fd70d58f360..7df2caf58bc1 100644
--- a/drivers/staging/imgtec/rogue/pvr_hwperf.c
+++ b/drivers/staging/imgtec/rogue/pvr_hwperf.c
@@ -232,7 +232,7 @@ PVRSRV_ERROR PVRSRVHWperfCreateDebugFs(void)
}
iError = PVRDebugFSCreateEntry("gpu_filter", g_sHWPerfDebugFs.psRootDir,
- &g_sSeqOps, HWPerfFilterSet,
+ &g_sSeqOps, HWPerfFilterSet, NULL, NULL,
(void *) RGX_HWPERF_STREAM_ID0_FW,
&g_sHWPerfDebugFs.psGpuFilterEntry);
if (iError)
@@ -242,7 +242,7 @@ PVRSRV_ERROR PVRSRVHWperfCreateDebugFs(void)
}
iError = PVRDebugFSCreateEntry("host_filter", g_sHWPerfDebugFs.psRootDir,
- &g_sSeqOps, HWPerfFilterSet,
+ &g_sSeqOps, HWPerfFilterSet, NULL, NULL,
(void *) RGX_HWPERF_STREAM_ID1_HOST,
&g_sHWPerfDebugFs.psHostFilterEntry);
if (iError)
diff --git a/drivers/staging/imgtec/rogue/pvrsrv.c b/drivers/staging/imgtec/rogue/pvrsrv.c
index 605e09daafba..5e5a7d7ea6b1 100644
--- a/drivers/staging/imgtec/rogue/pvrsrv.c
+++ b/drivers/staging/imgtec/rogue/pvrsrv.c
@@ -1012,7 +1012,7 @@ Error:
void IMG_CALLCONV PVRSRVDeInit(void *hDevice)
{
PVRSRV_DATA *psPVRSRVData = PVRSRVGetPVRSRVData();
- PVRSRV_ERROR eError;
+ PVRSRV_ERROR eError = PVRSRV_OK;
IMG_UINT32 i;
if (gpsPVRSRVData == NULL)
@@ -1043,8 +1043,16 @@ void IMG_CALLCONV PVRSRVDeInit(void *hDevice)
eError = OSEventObjectSignal(psPVRSRVData->hDevicesWatchdogEvObj);
PVR_LOG_IF_ERROR(eError, "OSEventObjectSignal");
}
- eError = OSThreadDestroy(gpsPVRSRVData->hDevicesWatchdogThread);
- gpsPVRSRVData->hDevicesWatchdogThread = NULL;
+ LOOP_UNTIL_TIMEOUT(OS_THREAD_DESTROY_TIMEOUT_US)
+ {
+ eError = OSThreadDestroy(gpsPVRSRVData->hDevicesWatchdogThread);
+ if (PVRSRV_OK == eError)
+ {
+ gpsPVRSRVData->hDevicesWatchdogThread = NULL;
+ break;
+ }
+ OSWaitus(OS_THREAD_DESTROY_TIMEOUT_US/OS_THREAD_DESTROY_RETRY_COUNT);
+ } END_LOOP_UNTIL_TIMEOUT();
PVR_LOG_IF_ERROR(eError, "OSThreadDestroy");
}
@@ -1065,8 +1073,16 @@ void IMG_CALLCONV PVRSRVDeInit(void *hDevice)
eError = OSEventObjectSignal(psPVRSRVData->hCleanupEventObject);
PVR_LOG_IF_ERROR(eError, "OSEventObjectSignal");
}
- eError = OSThreadDestroy(gpsPVRSRVData->hCleanupThread);
- gpsPVRSRVData->hCleanupThread = NULL;
+ LOOP_UNTIL_TIMEOUT(OS_THREAD_DESTROY_TIMEOUT_US)
+ {
+ eError = OSThreadDestroy(gpsPVRSRVData->hCleanupThread);
+ if (PVRSRV_OK == eError)
+ {
+ gpsPVRSRVData->hCleanupThread = NULL;
+ break;
+ }
+ OSWaitus(OS_THREAD_DESTROY_TIMEOUT_US/OS_THREAD_DESTROY_RETRY_COUNT);
+ } END_LOOP_UNTIL_TIMEOUT();
PVR_LOG_IF_ERROR(eError, "OSThreadDestroy");
}
diff --git a/drivers/staging/imgtec/rogue/pvrsrv.h b/drivers/staging/imgtec/rogue/pvrsrv.h
index 83e478761c3c..96bd4f358d29 100644
--- a/drivers/staging/imgtec/rogue/pvrsrv.h
+++ b/drivers/staging/imgtec/rogue/pvrsrv.h
@@ -55,6 +55,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "physheap.h"
#include "pvr_notifier.h"
+/*!
+ * For OSThreadDestroy(), which may require a retry
+ * Try for 100 ms to destroy an OS thread before failing
+ */
+#define OS_THREAD_DESTROY_TIMEOUT_US 100000ULL
+#define OS_THREAD_DESTROY_RETRY_COUNT 10
+
#include "connection_server.h"
#if defined(SUPPORT_GPUVIRT_VALIDATION)