diff options
author | Jonathan Hamilton <jonathan.hamilton@imgtec.com> | 2016-10-21 08:23:12 -0700 |
---|---|---|
committer | Thierry Strudel <tstrudel@google.com> | 2016-10-24 17:46:14 +0000 |
commit | ba519d2df3205a2d43ae0bcd3bfc489caf97ce71 (patch) | |
tree | d05357cd5e80a8b27688bf170e35e79d0be0d7b6 | |
parent | 8b19ac91b1ce42dba0e8ea64423ecad9f9c929ed (diff) | |
download | x86_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.c | 88 | ||||
-rw-r--r-- | drivers/staging/imgtec/pvr_sync.c | 6 | ||||
-rw-r--r-- | drivers/staging/imgtec/pvrversion.h | 6 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/cache_external.h | 6 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/cache_generic.c | 2 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/osfunc.c | 7 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvr_bridge_k.c | 2 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvr_debug.c | 10 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvr_debugfs.c | 59 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvr_debugfs.h | 5 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvr_gputrace.c | 3 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvr_hwperf.c | 4 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvrsrv.c | 26 | ||||
-rw-r--r-- | drivers/staging/imgtec/rogue/pvrsrv.h | 7 |
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) |