diff options
| author | Meizu OpenSource <patchwork@meizu.com> | 2016-08-15 10:19:42 +0800 |
|---|---|---|
| committer | Meizu OpenSource <patchwork@meizu.com> | 2016-08-15 10:19:42 +0800 |
| commit | d2e1446d81725c351dc73a03b397ce043fb18452 (patch) | |
| tree | 4dbc616b7f92aea39cd697a9084205ddb805e344 /drivers/misc/mediatek/gpu/ged/src | |
| download | android_kernel_m2note-d2e1446d81725c351dc73a03b397ce043fb18452.tar.gz | |
first commit
Diffstat (limited to 'drivers/misc/mediatek/gpu/ged/src')
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_base.c | 99 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_bridge.c | 79 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c | 178 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_hal.c | 284 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c | 217 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_log.c | 984 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_main.c | 338 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c | 141 | ||||
| -rw-r--r-- | drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c | 190 |
9 files changed, 2510 insertions, 0 deletions
diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_base.c b/drivers/misc/mediatek/gpu/ged/src/ged_base.c new file mode 100644 index 000000000..91ed382ca --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_base.c @@ -0,0 +1,99 @@ +/* + * (C) Copyright 2010 + * MediaTek <www.MediaTek.com> + * + * MTK GPU Extension Device + * + */ + +#include "ged_base.h" +#include <asm/page.h> +#include <linux/version.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)) +#ifndef AUTOCONF_INCLUDED +#include <linux/config.h> +#endif +#endif + +#include <asm/uaccess.h> + +unsigned long ged_copy_to_user(void __user *pvTo, const void *pvFrom, unsigned long ulBytes) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) + if (access_ok(VERIFY_WRITE, pvTo, ulBytes)) + { + return __copy_to_user(pvTo, pvFrom, ulBytes); + } + return ulBytes; +#else + return copy_to_user(pvTo, pvFrom, ulBytes); +#endif +} + +unsigned long ged_copy_from_user(void *pvTo, const void __user *pvFrom, unsigned long ulBytes) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) + if (access_ok(VERIFY_READ, pvFrom, ulBytes)) + { + return __copy_from_user(pvTo, pvFrom, ulBytes); + } + return ulBytes; +#else + return copy_from_user(pvTo, pvFrom, ulBytes); +#endif +} + +void* ged_alloc(int i32Size) +{ + void *pvBuf; + + if (i32Size <= PAGE_SIZE) + { + pvBuf = kmalloc(i32Size, GFP_KERNEL); + } + else + { + pvBuf = vmalloc(i32Size); + } + + return pvBuf; +} + +void ged_free(void* pvBuf, int i32Size) +{ + if (pvBuf) + { + if (i32Size <= PAGE_SIZE) + { + kfree(pvBuf); + } + else + { + vfree(pvBuf); + } + } +} + +long ged_get_pid(void) +{ + if (in_interrupt()) + { + return 0xffffffffL; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) + return (long)current->pgrp; +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)) + return (long)task_tgid_nr(current); +#else + return (long)current->tgid; +#endif +#endif +} + diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_bridge.c b/drivers/misc/mediatek/gpu/ged/src/ged_bridge.c new file mode 100644 index 000000000..99eccd774 --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_bridge.c @@ -0,0 +1,79 @@ +#include <linux/kernel.h> +#include <linux/mtk_gpu_utility.h> + +#include "ged_base.h" +#include "ged_bridge.h" +#include "ged_log.h" +#include "ged_profile_dvfs.h" +#include "ged_monitor_3D_fence.h" + +//----------------------------------------------------------------------------- +int ged_bridge_log_buf_get( + GED_BRIDGE_IN_LOGBUFGET *psLogBufGetIN, + GED_BRIDGE_OUT_LOGBUFGET *psLogBufGetOUT) +{ + psLogBufGetOUT->hLogBuf = ged_log_buf_get(psLogBufGetIN->acName); + psLogBufGetOUT->eError = psLogBufGetOUT->hLogBuf ? GED_OK : GED_ERROR_FAIL; + return 0; +} +//----------------------------------------------------------------------------- +int ged_bridge_log_buf_write( + GED_BRIDGE_IN_LOGBUFWRITE *psLogBufWriteIN, + GED_BRIDGE_OUT_LOGBUFWRITE *psLogBufWriteOUT) +{ + psLogBufWriteOUT->eError = + ged_log_buf_print2(psLogBufWriteIN->hLogBuf, psLogBufWriteIN->attrs, psLogBufWriteIN->acLogBuf); + +#if 0 + if (ged_log_buf_write( + psLogBufWriteIN->hLogBuf, + /*from user*/psLogBufWriteIN->acLogBuf, + GED_BRIDGE_IN_LOGBUF_SIZE) > 0) + { + psLogBufWriteOUT->eError = GED_OK; + } + else + { + psLogBufWriteOUT->eError = GED_ERROR_FAIL; + } +#endif + return 0; +} +//----------------------------------------------------------------------------- +int ged_bridge_log_buf_reset( + GED_BRIDGE_IN_LOGBUFRESET *psLogBufResetIn, + GED_BRIDGE_OUT_LOGBUFRESET *psLogBufResetOUT) +{ + psLogBufResetOUT->eError = ged_log_buf_reset(psLogBufResetIn->hLogBuf); + return 0; +} +//----------------------------------------------------------------------------- +int ged_bridge_boost_gpu_freq( + GED_BRIDGE_IN_BOOSTGPUFREQ *psBoostGpuFreqIN, + GED_BRIDGE_OUT_BOOSTGPUFREQ *psBoostGpuFreqOUT) +{ +#if 1 + psBoostGpuFreqOUT->eError = mtk_boost_gpu_freq() ? GED_OK : GED_ERROR_FAIL; +#else + unsigned int ui32Count; + if (mtk_custom_get_gpu_freq_level_count(&ui32Count)) + { + int i32Level = (ui32Count - 1) - GED_BOOST_GPU_FREQ_LEVEL_MAX - psBoostGpuFreqIN->eGPUFreqLevel; + mtk_boost_gpu_freq(i32Level); + psBoostGpuFreqOUT->eError = GED_OK; + } + else + { + psBoostGpuFreqOUT->eError = GED_ERROR_FAIL; + } +#endif + return 0; +} +//----------------------------------------------------------------------------- +int ged_bridge_monitor_3D_fence( + GED_BRIDGE_IN_MONITOR3DFENCE *psMonitor3DFenceINT, + GED_BRIDGE_OUT_MONITOR3DFENCE *psMonitor3DFenceOUT) +{ + psMonitor3DFenceOUT->eError = ged_monitor_3D_fence_add(psMonitor3DFenceINT->fd); + return 0; +} diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c b/drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c new file mode 100644 index 000000000..0e208903d --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_debugFS.c @@ -0,0 +1,178 @@ +#include <linux/module.h> +#include <linux/slab.h> + +#include <linux/debugfs.h> + +#include "ged_base.h" +#include "ged_debugFS.h" + +#define GED_DEBUGFS_DIR_NAME "ged" + +static struct dentry *gpsDebugFSEntryDir = NULL; + +typedef struct _GED_DEBUGFS_PRIV_DATA_ +{ + struct seq_operations* psReadOps; + GED_ENTRY_WRITE_FUNC* pfnWrite; + void* pvData; +} GED_DEBUGFS_PRIV_DATA; +//----------------------------------------------------------------------------- +static GED_ERROR ged_debugFS_open(struct inode *psINode, struct file *psFile) +{ + GED_DEBUGFS_PRIV_DATA *psPrivData = (GED_DEBUGFS_PRIV_DATA *)psINode->i_private; + int iResult; + + iResult = seq_open(psFile, psPrivData->psReadOps); + if (iResult == 0) + { + struct seq_file *psSeqFile = psFile->private_data; + + psSeqFile->private = psPrivData->pvData; + + return GED_OK; + } + + return GED_ERROR_FAIL; +} +//----------------------------------------------------------------------------- +static ssize_t ged_debugFS_write( + struct file* psFile, + const char __user* pszBuffer, + size_t uiCount, + loff_t* puiPosition) +{ + struct inode *psINode = psFile->f_path.dentry->d_inode; + GED_DEBUGFS_PRIV_DATA *psPrivData = (GED_DEBUGFS_PRIV_DATA *)psINode->i_private; + + if (psPrivData->pfnWrite == NULL) + { + return -EIO; + } + + return psPrivData->pfnWrite(pszBuffer, uiCount, *puiPosition, psPrivData->pvData); +} +//----------------------------------------------------------------------------- +static const struct file_operations gsGEDDebugFSFileOps = +{ + .owner = THIS_MODULE, + .open = ged_debugFS_open, + .read = seq_read, + .write = ged_debugFS_write, + .llseek = seq_lseek, + .release = seq_release, +}; +//----------------------------------------------------------------------------- +GED_ERROR ged_debugFS_create_entry( + const char* pszName, + void* pvDir, + struct seq_operations* psReadOps, + GED_ENTRY_WRITE_FUNC* pfnWrite, + void* pvData, + struct dentry** ppsEntry) +{ + GED_DEBUGFS_PRIV_DATA* psPrivData; + struct dentry* psEntry; + umode_t uiMode; + + //assert(gpkDebugFSEntryDir != NULL); + + psPrivData = ged_alloc(sizeof(GED_DEBUGFS_PRIV_DATA)); + if (psPrivData == NULL) + { + return GED_ERROR_OOM; + } + + psPrivData->psReadOps = psReadOps; + psPrivData->pfnWrite = pfnWrite; + psPrivData->pvData = pvData; + + uiMode = S_IFREG; + + if (psReadOps != NULL) + { + uiMode |= S_IRUGO; + } + + if (pfnWrite != NULL) + { + uiMode |= S_IWUSR; + } + + psEntry = debugfs_create_file(pszName, + uiMode, + (pvDir != NULL) ? (struct dentry *)pvDir : gpsDebugFSEntryDir, + psPrivData, + &gsGEDDebugFSFileOps); + if (IS_ERR(psEntry)) + { + GED_LOGE("Failed to create '%s' debugfs entry\n", pszName); + return GED_ERROR_FAIL; + } + + *ppsEntry = psEntry; + + return GED_OK; +} +//----------------------------------------------------------------------------- +void ged_debugFS_remove_entry(struct dentry *psEntry) +{ + if (psEntry->d_inode->i_private != NULL) + { + ged_free(psEntry->d_inode->i_private, sizeof(GED_DEBUGFS_PRIV_DATA)); + } + + debugfs_remove(psEntry); +} +//----------------------------------------------------------------------------- +GED_ERROR ged_debugFS_create_entry_dir( + const char* pszName, + struct dentry* psParentDir, + struct dentry** ppsDir) +{ + struct dentry *psDir; + + if (pszName == NULL || ppsDir == NULL) + { + return GED_ERROR_INVALID_PARAMS; + } + + psDir = debugfs_create_dir(pszName, (psParentDir) ? psParentDir : gpsDebugFSEntryDir); + if (psDir == NULL) + { + GED_LOGE("Failed to create '%s' debugfs directory\n", pszName); + return GED_ERROR_OOM; + } + + *ppsDir = psDir; + + return GED_OK; +} +//----------------------------------------------------------------------------- +void ged_debugFS_remove_entry_dir(struct dentry *psDir) +{ + debugfs_remove(psDir); +} +//----------------------------------------------------------------------------- +GED_ERROR ged_debugFS_init(void) +{ + //assert(gpkDebugFSEntryDir == NULL); + + gpsDebugFSEntryDir = debugfs_create_dir(GED_DEBUGFS_DIR_NAME, NULL); + if (gpsDebugFSEntryDir == NULL) + { + GED_LOGE("Failed to create '%s' debugfs root directory\n", GED_DEBUGFS_DIR_NAME); + return GED_ERROR_OOM; + } + + return GED_OK; +} +//----------------------------------------------------------------------------- +void ged_debugFS_exit(void) +{ + //assert(gpkDebugFSEntryDir != NULL); + + debugfs_remove(gpsDebugFSEntryDir); + gpsDebugFSEntryDir = NULL; +} +//----------------------------------------------------------------------------- + diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_hal.c b/drivers/misc/mediatek/gpu/ged/src/ged_hal.c new file mode 100644 index 000000000..3f3fe293c --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_hal.c @@ -0,0 +1,284 @@ +#include <linux/version.h> +#include <asm/io.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/genalloc.h> +#include <linux/sched.h> +#include <linux/mutex.h> +#include <linux/xlog.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/mtk_gpu_utility.h> + +#include "ged_base.h" +#include "ged_hal.h" +#include "ged_debugFS.h" + +static struct dentry* gpsHALDir = NULL; +static struct dentry* gpsTotalGPUFreqLevelCountEntry = NULL; +static struct dentry* gpsCustomBoostGPUFreqEntry = NULL; +static struct dentry* gpsCustomUpboundGPUFreqEntry = NULL; + +//----------------------------------------------------------------------------- +static void* ged_total_gpu_freq_level_count_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition) +{ + if (0 == *puiPosition) + { + return 1; + } + + return NULL; +} +//----------------------------------------------------------------------------- +static void ged_total_gpu_freq_level_count_seq_stop(struct seq_file *psSeqFile, void *pvData) +{ + +} +//----------------------------------------------------------------------------- +static void* ged_total_gpu_freq_level_count_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition) +{ + return NULL; +} +//----------------------------------------------------------------------------- +static int ged_total_gpu_freq_level_count_seq_show(struct seq_file *psSeqFile, void *pvData) +{ + if (pvData != NULL) + { + unsigned int ui32FreqLevelCount; + if (false == mtk_custom_get_gpu_freq_level_count(&ui32FreqLevelCount)) + { + ui32FreqLevelCount = 0; + } + seq_printf(psSeqFile, "%u\n", ui32FreqLevelCount); + } + + return 0; +} +//----------------------------------------------------------------------------- +static struct seq_operations gsTotalGPUFreqLevelCountReadOps = +{ + .start = ged_total_gpu_freq_level_count_seq_start, + .stop = ged_total_gpu_freq_level_count_seq_stop, + .next = ged_total_gpu_freq_level_count_seq_next, + .show = ged_total_gpu_freq_level_count_seq_show, +}; +//----------------------------------------------------------------------------- +static ssize_t ged_custom_boost_gpu_freq_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData) +{ +#define GED_HAL_DEBUGFS_SIZE 64 + char acBuffer[GED_HAL_DEBUGFS_SIZE]; + + int i32Value; + + if ((0 < uiCount) && (uiCount < GED_HAL_DEBUGFS_SIZE)) + { + if (0 == ged_copy_from_user(acBuffer, pszBuffer, uiCount)) + { + acBuffer[uiCount] = '\0'; + if (sscanf(acBuffer, "%d", &i32Value) == 1) + { + if (i32Value < 0) + i32Value = 0; + mtk_custom_boost_gpu_freq(i32Value); + } + //else if (...) //for other commands + //{ + //} + } + } + + return uiCount; +} +//----------------------------------------------------------------------------- +static void* ged_custom_boost_gpu_freq_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition) +{ + if (0 == *puiPosition) + { + return 1; + } + + return NULL; +} +//----------------------------------------------------------------------------- +static void ged_custom_boost_gpu_freq_seq_stop(struct seq_file *psSeqFile, void *pvData) +{ + +} +//----------------------------------------------------------------------------- +static void* ged_custom_boost_gpu_freq_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition) +{ + return NULL; +} +//----------------------------------------------------------------------------- +static int ged_custom_boost_gpu_freq_seq_show(struct seq_file *psSeqFile, void *pvData) +{ + if (pvData != NULL) + { + unsigned int ui32BoostGpuFreqLevel; + if (false == mtk_get_custom_boost_gpu_freq(&ui32BoostGpuFreqLevel)) + { + ui32BoostGpuFreqLevel = 0; + } + seq_printf(psSeqFile, "%u\n", ui32BoostGpuFreqLevel); + } + + return 0; +} +//----------------------------------------------------------------------------- +static struct seq_operations gsCustomBoostGpuFreqReadOps = +{ + .start = ged_custom_boost_gpu_freq_seq_start, + .stop = ged_custom_boost_gpu_freq_seq_stop, + .next = ged_custom_boost_gpu_freq_seq_next, + .show = ged_custom_boost_gpu_freq_seq_show, +}; +//----------------------------------------------------------------------------- +static ssize_t ged_custom_upbound_gpu_freq_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData) +{ +#define GED_HAL_DEBUGFS_SIZE 64 + char acBuffer[GED_HAL_DEBUGFS_SIZE]; + + int i32Value; + + if ((0 < uiCount) && (uiCount < GED_HAL_DEBUGFS_SIZE)) + { + if (0 == ged_copy_from_user(acBuffer, pszBuffer, uiCount)) + { + acBuffer[uiCount] = '\0'; + if (sscanf(acBuffer, "%d", &i32Value) == 1) + { + if (i32Value < 0) + i32Value = 0; + mtk_custom_upbound_gpu_freq(i32Value); + } + //else if (...) //for other commands + //{ + //} + } + } + + return uiCount; +} +//----------------------------------------------------------------------------- +static void* ged_custom_upbound_gpu_freq_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition) +{ + if (0 == *puiPosition) + { + return 1; + } + + return NULL; +} +//----------------------------------------------------------------------------- +static void ged_custom_upbound_gpu_freq_seq_stop(struct seq_file *psSeqFile, void *pvData) +{ + +} +//----------------------------------------------------------------------------- +static void* ged_custom_upbound_gpu_freq_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition) +{ + return NULL; +} +//----------------------------------------------------------------------------- +static int ged_custom_upbound_gpu_freq_seq_show(struct seq_file *psSeqFile, void *pvData) +{ + if (pvData != NULL) + { + unsigned int ui32UpboundGpuFreqLevel; + if (false == mtk_get_custom_upbound_gpu_freq(&ui32UpboundGpuFreqLevel)) + { + ui32UpboundGpuFreqLevel = 0; + seq_printf(psSeqFile, "call mtk_get_custom_upbound_gpu_freq false\n"); + } + seq_printf(psSeqFile, "%u\n", ui32UpboundGpuFreqLevel); + } + + return 0; +} +//----------------------------------------------------------------------------- +static struct seq_operations gsCustomUpboundGpuFreqReadOps = +{ + .start = ged_custom_upbound_gpu_freq_seq_start, + .stop = ged_custom_upbound_gpu_freq_seq_stop, + .next = ged_custom_upbound_gpu_freq_seq_next, + .show = ged_custom_upbound_gpu_freq_seq_show, +}; +//----------------------------------------------------------------------------- +GED_ERROR ged_hal_init(void) +{ + GED_ERROR err = GED_OK; + + err = ged_debugFS_create_entry_dir( + "hal", + NULL, + &gpsHALDir); + + if (unlikely(err != GED_OK)) + { + err = GED_ERROR_FAIL; + GED_LOGE("ged: failed to create hal dir!\n"); + goto ERROR; + } + + /* Feedback the gpu freq level count */ + err = ged_debugFS_create_entry( + "total_gpu_freq_level_count", + gpsHALDir, + &gsTotalGPUFreqLevelCountReadOps, + NULL, + NULL, + &gpsTotalGPUFreqLevelCountEntry); + + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to create total_gpu_freq_level_count entry!\n"); + goto ERROR; + } + + /* Control the gpu freq */ + err = ged_debugFS_create_entry( + "custom_boost_gpu_freq", + gpsHALDir, + &gsCustomBoostGpuFreqReadOps, + ged_custom_boost_gpu_freq_write_entry, + NULL, + &gpsCustomBoostGPUFreqEntry); + + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to create custom_boost_gpu_freq entry!\n"); + goto ERROR; + } + + /* Control the gpu freq */ + err = ged_debugFS_create_entry( + "custom_upbound_gpu_freq", + gpsHALDir, + &gsCustomUpboundGpuFreqReadOps, + ged_custom_upbound_gpu_freq_write_entry, + NULL, + &gpsCustomUpboundGPUFreqEntry); + + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to create custom_upbound_gpu_freq entry!\n"); + goto ERROR; + } + + return err; + +ERROR: + + ged_hal_exit(); + + return err; +} +//----------------------------------------------------------------------------- +void ged_hal_exit(void) +{ + ged_debugFS_remove_entry(gpsCustomUpboundGPUFreqEntry); + ged_debugFS_remove_entry(gpsCustomBoostGPUFreqEntry); + ged_debugFS_remove_entry(gpsTotalGPUFreqLevelCountEntry); + ged_debugFS_remove_entry_dir(gpsHALDir); +} +//----------------------------------------------------------------------------- diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c b/drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c new file mode 100644 index 000000000..456ca364d --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_hashtable.c @@ -0,0 +1,217 @@ +#include "ged_base.h" +#include "ged_hashtable.h" +#include <linux/hashtable.h> + +typedef struct GED_HASHTABLE_TAG +{ + unsigned int ui32Bits; + unsigned int ui32Length; + unsigned int ui32CurrentID; + unsigned int ui32Count; + struct hlist_head* psHashTable; +} GED_HASHTABLE; + +typedef struct GED_HASHNODE_TAG +{ + unsigned int ui32ID; + void* pvoid; + struct hlist_node sNode; +} GED_HASHNODE; + +#define GED_HASHTABLE_INIT_ID 1234 // 0 = invalid + +void* __ged_hashtable_find(struct hlist_head *head, unsigned int ui32ID) +{ + GED_HASHNODE* psHN; + hlist_for_each_entry_rcu(psHN, head, sNode) + { + if (psHN->ui32ID == ui32ID) + { + return psHN; + } + } + return NULL; +} + +static int ged_hash(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID) +{ + GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable; + return hash_32(ui32ID, psHT->ui32Bits); +} + +GED_HASHTABLE_HANDLE ged_hashtable_create(unsigned int ui32Bits) +{ + GED_HASHTABLE* psHT; + unsigned int i; + + if (ui32Bits > 20) + { + // 1048576 slots !? + // Need to check the necessary + return NULL; + } + + psHT = (GED_HASHTABLE*)ged_alloc(sizeof(GED_HASHTABLE)); + if (psHT) + { + psHT->ui32Bits = ui32Bits; + psHT->ui32Length = 1 << ui32Bits; + psHT->ui32CurrentID = GED_HASHTABLE_INIT_ID; // 0 = invalid + psHT->psHashTable = (struct hlist_head*)ged_alloc(psHT->ui32Length * sizeof(struct hlist_head)); + if (psHT->psHashTable) + { + for (i = 0; i < psHT->ui32Length; i++) + { + INIT_HLIST_HEAD(&psHT->psHashTable[i]); + } + return (GED_HASHTABLE_HANDLE)psHT; + } + } + + ged_hashtable_destroy(psHT); + return NULL; +} + +void ged_hashtable_destroy(GED_HASHTABLE_HANDLE hHashTable) +{ + GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable; + if (psHT) + { + int i = 0; + while(psHT->ui32Count > 0) + { + unsigned int ui32ID = 0; + GED_HASHNODE* psHN; + // get one to be freed + for (;i < psHT->ui32Length; i++) + { + struct hlist_head *head = &psHT->psHashTable[i]; + hlist_for_each_entry_rcu(psHN, head, sNode) + { + ui32ID = psHN->ui32ID; + break; + } + if (0 < ui32ID) + { + break; + } + } + + if (i >= psHT->ui32Length) + { + break; + } + + ged_hashtable_remove(psHT, ui32ID); + } + + /* free the hash table */ + ged_free(psHT->psHashTable, psHT->ui32Length * sizeof(struct hlist_head)); + ged_free(psHT, sizeof(GED_HASHTABLE)); + } +} + +GED_ERROR ged_hashtable_insert(GED_HASHTABLE_HANDLE hHashTable, void* pvoid, unsigned int* pui32ID) +{ + GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable; + GED_HASHNODE* psHN = NULL; + unsigned int ui32Hash, ui32ID; + + if ((!psHT) || (!pui32ID)) + { + return GED_ERROR_INVALID_PARAMS; + } + + ui32ID = psHT->ui32CurrentID + 1; + while(1) + { + ui32Hash = ged_hash(psHT, ui32ID); + psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID); + if (psHN != NULL) + { + ui32ID++; + if (ui32ID == 0)//skip the value 0 + { + ui32ID = 1; + } + if (ui32ID == psHT->ui32CurrentID) + { + return GED_ERROR_FAIL; + } + } + else + { + break; + } + }; + + psHN = (GED_HASHNODE*)ged_alloc(sizeof(GED_HASHNODE)); + if (psHN) + { + psHN->pvoid = pvoid; + psHN->ui32ID = ui32ID; + psHT->ui32CurrentID = ui32ID; + *pui32ID = ui32ID; + hlist_add_head_rcu(&psHN->sNode, &psHT->psHashTable[ui32Hash]); + psHT->ui32Count += 1; + return GED_OK; + } + + return GED_ERROR_OOM; +} + +void ged_hashtable_remove(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID) +{ + GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable; + if (psHT) + { + unsigned int ui32Hash = ged_hash(psHT, ui32ID); + GED_HASHNODE* psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID); + if (psHN) + { + hlist_del_rcu(&psHN->sNode); + synchronize_rcu(); + ged_free(psHN, sizeof(GED_HASHNODE)); + psHT->ui32Count -= 1; + } + } +} + +void* ged_hashtable_find(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID) +{ + GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable; + if (psHT) + { + unsigned int ui32Hash = ged_hash(psHT, ui32ID); + GED_HASHNODE* psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID); + if (psHN) + { + return psHN->pvoid; + } +#ifdef GED_DEBUG + if (ui32ID != 0) + { + GED_LOGE("ged_hashtable_find: ui32ID=%u ui32Hash=%u psHN=%p\n", ui32ID, ui32Hash, psHN); + } +#endif + } + return NULL; +} + +GED_ERROR ged_hashtable_set(GED_HASHTABLE_HANDLE hHashTable, unsigned int ui32ID, void* pvoid) +{ + GED_HASHTABLE* psHT = (GED_HASHTABLE*)hHashTable; + if (psHT) + { + unsigned int ui32Hash = ged_hash(psHT, ui32ID); + GED_HASHNODE* psHN = __ged_hashtable_find(&psHT->psHashTable[ui32Hash], ui32ID); + if (psHN) + { + psHN->pvoid = pvoid; + return GED_OK; + } + } + + return GED_ERROR_INVALID_PARAMS; +} + diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_log.c b/drivers/misc/mediatek/gpu/ged/src/ged_log.c new file mode 100644 index 000000000..2e7b691c7 --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_log.c @@ -0,0 +1,984 @@ +#include <linux/version.h> +#include <asm/io.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/genalloc.h> +#include <linux/sched.h> +#include <linux/mutex.h> +#include <linux/xlog.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/rtc.h> + +#include "ged_base.h" +#include "ged_log.h" +#include "ged_debugFS.h" +#include "ged_profile_dvfs.h" +#include "ged_hashtable.h" + +enum +{ + /* 0x00 - 0xff reserved for internal buffer type */ + + /* rewrite the oldest log when buffer is full */ + GED_LOG_ATTR_RINGBUFFER = 0x1, + /* stop logging when buffer is full */ + GED_LOG_ATTR_QUEUEBUFFER = 0x2, + /* increase buffersize when buffer is full */ + GED_LOG_ATTR_AUTO_INCREASE = 0x4, +}; + +typedef struct GED_LOG_BUF_LINE_TAG +{ + int offset; + int tattrs; + long long time; + long int time_usec; + int pid; + int tid; +} GED_LOG_BUF_LINE; + +typedef struct GED_LOG_BUF_TAG +{ + GED_LOG_BUF_TYPE eType; + int attrs; + + void *pMemory; + int i32MemorySize; + + GED_LOG_BUF_LINE *psLine; + char *pcBuffer; + int i32LineCount; + int i32BufferSize; + int i32LineCurrent; + int i32BufferCurrent; + + spinlock_t sSpinLock; + unsigned long ui32IRQFlags; + + char acName[GED_LOG_BUF_NAME_LENGTH]; + char acNodeName[GED_LOG_BUF_NODE_NAME_LENGTH]; + + struct dentry* psEntry; + + struct list_head sList; + + unsigned int ui32HashNodeID; + +} GED_LOG_BUF; + +typedef struct GED_LOG_LISTEN_TAG +{ + GED_LOG_BUF_HANDLE *pCBHnd; + char acName[GED_LOG_BUF_NAME_LENGTH]; + struct list_head sList; +} GED_LOG_LISTEN; + +typedef struct GED_LOG_BUF_LIST_TAG +{ + rwlock_t sLock; + struct list_head sList_buf; + struct list_head sList_listen; +} GED_LOG_BUF_LIST; + +static GED_LOG_BUF_LIST gsGEDLogBufList = { + .sLock = __RW_LOCK_UNLOCKED(gsGEDLogBufList.sLock), + .sList_buf = LIST_HEAD_INIT(gsGEDLogBufList.sList_buf), + .sList_listen = LIST_HEAD_INIT(gsGEDLogBufList.sList_listen), +}; + +static struct dentry* gpsGEDLogEntry = NULL; +static struct dentry* gpsGEDLogBufsDir = NULL; + +static GED_HASHTABLE_HANDLE ghHashTable = NULL; + +//----------------------------------------------------------------------------- +// +// GED Log Buf +// +//----------------------------------------------------------------------------- +static GED_LOG_BUF* ged_log_buf_from_handle(GED_LOG_BUF_HANDLE hLogBuf) +{ + return ged_hashtable_find(ghHashTable, (unsigned int)hLogBuf); +} + +static GED_ERROR __ged_log_buf_vprint(GED_LOG_BUF *psGEDLogBuf, const char *fmt, va_list args, int attrs) +{ + int buf_n; + int len; + + if (!psGEDLogBuf) + return GED_OK; + + spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + + /* if OOM */ + if (psGEDLogBuf->i32LineCurrent >= psGEDLogBuf->i32LineCount || + psGEDLogBuf->i32BufferCurrent + 256 > psGEDLogBuf->i32BufferSize) + { + if (attrs & GED_LOG_ATTR_RINGBUFFER) + { + /* for ring buffer, we start over. */ + psGEDLogBuf->i32LineCurrent = 0; + psGEDLogBuf->i32BufferCurrent = 0; + } + else if (attrs & GED_LOG_ATTR_QUEUEBUFFER) + { + if (attrs & GED_LOG_ATTR_AUTO_INCREASE) + { + int newLineCount, newBufferSize; + + /* incease min(25%, 1MB) */ + if ((psGEDLogBuf->i32LineCount >> 2) <= 1024 * 1024) + { + newLineCount = psGEDLogBuf->i32LineCount + (psGEDLogBuf->i32LineCount >> 2); + newBufferSize = psGEDLogBuf->i32BufferSize + (psGEDLogBuf->i32BufferSize >> 2); + } + else + { + newLineCount = psGEDLogBuf->i32LineCount + 4096; + newBufferSize = psGEDLogBuf->i32BufferSize + 1024 * 1024; + } + + spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + if (ged_log_buf_resize(psGEDLogBuf->ui32HashNodeID, newLineCount, newBufferSize) != GED_OK) + { + return GED_ERROR_OOM; + } + spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + } + else + { + /* for queuebuffer only, we skip the log. */ + spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + return GED_ERROR_OOM; + } + } + } + + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].offset = psGEDLogBuf->i32BufferCurrent; + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tattrs = 0; + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time = 0; + + /* record the kernel time */ + if (attrs & GED_LOG_ATTR_TIME) + { + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tattrs = GED_LOG_ATTR_TIME; + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time = cpu_clock(smp_processor_id()); + } + + /* record the user time */ + if (attrs & GED_LOG_ATTR_TIME_TPT) + { + struct timeval time; + unsigned long local_time; + + do_gettimeofday(&time); + local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); + + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tattrs = GED_LOG_ATTR_TIME_TPT; + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time = local_time; + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].time_usec = time.tv_usec; + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].pid = current->tgid; + psGEDLogBuf->psLine[psGEDLogBuf->i32LineCurrent].tid = current->pid; + } + + buf_n = psGEDLogBuf->i32BufferSize - psGEDLogBuf->i32BufferCurrent; + len = vsnprintf(psGEDLogBuf->pcBuffer + psGEDLogBuf->i32BufferCurrent, buf_n, fmt, args); + + if (len > buf_n) len = buf_n; + + buf_n -= len; + + if (attrs & GED_LOG_ATTR_RINGBUFFER) + { + int i; + int check = 10 + 1; /* we check the following 10 items. */ + int a = psGEDLogBuf->i32BufferCurrent; + int b = psGEDLogBuf->i32BufferCurrent + len + 2; + + for (i = psGEDLogBuf->i32LineCurrent+1; --check && i < psGEDLogBuf->i32LineCount; ++i) + { + int pos = psGEDLogBuf->psLine[i].offset; + if (pos >= a && pos < b) + psGEDLogBuf->psLine[i].offset = -1; + } + + if (check && i == psGEDLogBuf->i32LineCount) + { + for (i = 0; --check && i < psGEDLogBuf->i32LineCurrent; ++i) + { + int pos = psGEDLogBuf->psLine[i].offset; + + if (pos >= a && pos < b) + psGEDLogBuf->psLine[i].offset = -1; + } + } + } + + /* update current */ + psGEDLogBuf->i32BufferCurrent += len + 2; + psGEDLogBuf->i32LineCurrent += 1; + + spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + + return GED_OK; +} + +static GED_ERROR __ged_log_buf_print(GED_LOG_BUF *psGEDLogBuf, const char *fmt, ...) +{ + va_list args; + GED_ERROR err; + + va_start(args, fmt); + err = __ged_log_buf_vprint(psGEDLogBuf, fmt, args, psGEDLogBuf->attrs); + va_end(args); + + return err; +} + +static int __ged_log_buf_write(GED_LOG_BUF *psGEDLogBuf, const char __user *pszBuffer, int i32Count) +{ + int cnt; + char buf[256]; + + if (!psGEDLogBuf) + { + return 0; + } + + cnt = (i32Count >= 256) ? 255 : i32Count; + + ged_copy_from_user(buf, pszBuffer, cnt); + + buf[cnt] = 0; + + __ged_log_buf_print(psGEDLogBuf, buf); + + return cnt; +} + +static void __ged_log_buf_check_get_early_list(GED_LOG_BUF_HANDLE hLogBuf, const char *pszName) +{ + struct list_head *psListEntry, *psListEntryTemp, *psList; + GED_LOG_LISTEN *psFound = NULL, *psLogListen; + + read_lock_bh(&gsGEDLogBufList.sLock); + + psList = &gsGEDLogBufList.sList_listen; + list_for_each_safe(psListEntry, psListEntryTemp, psList) + { + psLogListen = list_entry(psListEntry, GED_LOG_LISTEN, sList); + if (0 == strcmp(psLogListen->acName, pszName)) + { + psFound = psLogListen; + break; + } + } + + read_unlock_bh(&gsGEDLogBufList.sLock); + + if (psFound) + { + write_lock_bh(&gsGEDLogBufList.sLock); + *psFound->pCBHnd = hLogBuf; + list_del(&psFound->sList); + write_unlock_bh(&gsGEDLogBufList.sLock); + } +} + +static ssize_t ged_log_buf_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData) +{ + return (ssize_t)__ged_log_buf_write((GED_LOG_BUF *)pvData, pszBuffer, (int)uiCount); +} +//----------------------------------------------------------------------------- +static void* ged_log_buf_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition) +{ + GED_LOG_BUF *psGEDLogBuf = (GED_LOG_BUF *)psSeqFile->private; + + if (0 == *puiPosition) + { + return psGEDLogBuf; + } + return NULL; +} +//----------------------------------------------------------------------------- +static void ged_log_buf_seq_stop(struct seq_file *psSeqFile, void *pvData) +{ + +} +//----------------------------------------------------------------------------- +static void* ged_log_buf_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition) +{ + (*puiPosition)++; + + return NULL; +} +//----------------------------------------------------------------------------- +static int ged_log_buf_seq_show_print(struct seq_file *psSeqFile, GED_LOG_BUF *psGEDLogBuf, int i) +{ + int err = 0; + GED_LOG_BUF_LINE *line; + + line = &psGEDLogBuf->psLine[i]; + + if (line->offset >= 0) + { + if (line->tattrs & GED_LOG_ATTR_TIME) + { + unsigned long long t; + unsigned long nanosec_rem; + + t = line->time; + nanosec_rem = do_div(t, 1000000000); + + seq_printf(psSeqFile,"[%5llu.%06lu] ", t, nanosec_rem / 1000); + } + + if (line->tattrs & GED_LOG_ATTR_TIME_TPT) + { + unsigned long local_time; + struct rtc_time tm; + + local_time = line->time; + rtc_time_to_tm(local_time, &tm); + + seq_printf(psSeqFile,"%02d-%02d %02d:%02d:%02d.%06lu %5d %5d ", + /*tm.tm_year + 1900,*/ tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, + line->time_usec, line->pid, line->tid); + } + + err = seq_printf(psSeqFile, "%s\n", psGEDLogBuf->pcBuffer + line->offset); + } + + return err; +} + +static int ged_log_buf_seq_show(struct seq_file *psSeqFile, void *pvData) +{ + GED_LOG_BUF *psGEDLogBuf = (GED_LOG_BUF *)pvData; + + if (psGEDLogBuf != NULL) + { + int i; + + spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + + if (psGEDLogBuf->acName[0] != '\0') + { + seq_printf(psSeqFile, "---------- %s (%d/%d) ----------\n", + psGEDLogBuf->acName, psGEDLogBuf->i32BufferCurrent, psGEDLogBuf->i32BufferSize); + } + + if (psGEDLogBuf->attrs & GED_LOG_ATTR_RINGBUFFER) + { + for (i = psGEDLogBuf->i32LineCurrent; i < psGEDLogBuf->i32LineCount; ++i) + { + if (0 != ged_log_buf_seq_show_print(psSeqFile, psGEDLogBuf, i)) + break; + } + + //seq_printf(psSeqFile, " > ---------- start over ----------\n"); + + for (i = 0; i < psGEDLogBuf->i32LineCurrent; ++i) + { + if (0 != ged_log_buf_seq_show_print(psSeqFile, psGEDLogBuf, i)) + break; + } + } + else if (psGEDLogBuf->attrs & GED_LOG_ATTR_QUEUEBUFFER) + { + for (i = 0; i < psGEDLogBuf->i32LineCount; ++i) + { + if (0 != ged_log_buf_seq_show_print(psSeqFile, psGEDLogBuf, i)) + break; + } + } + + spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + } + + return 0; +} +//----------------------------------------------------------------------------- +static struct seq_operations gsGEDLogBufReadOps = +{ + .start = ged_log_buf_seq_start, + .stop = ged_log_buf_seq_stop, + .next = ged_log_buf_seq_next, + .show = ged_log_buf_seq_show, +}; +//----------------------------------------------------------------------------- +GED_LOG_BUF_HANDLE ged_log_buf_alloc( + int i32MaxLineCount, + int i32MaxBufferSizeByte, + GED_LOG_BUF_TYPE eType, + const char* pszName, + const char* pszNodeName) +{ + GED_LOG_BUF *psGEDLogBuf; + GED_ERROR error; + + if (((!pszName) && (!pszNodeName)) || (i32MaxLineCount <= 0) || (i32MaxBufferSizeByte <= 0)) + { + return (GED_LOG_BUF_HANDLE)0; + } + + psGEDLogBuf = (GED_LOG_BUF*)ged_alloc(sizeof(GED_LOG_BUF)); + if (NULL == psGEDLogBuf) + { + GED_LOGE("ged: failed to allocate log buf!\n"); + return (GED_LOG_BUF_HANDLE)0; + } + + psGEDLogBuf->eType = eType; + + switch (eType) + { + case GED_LOG_BUF_TYPE_RINGBUFFER: + psGEDLogBuf->attrs = GED_LOG_ATTR_RINGBUFFER; + break; + case GED_LOG_BUF_TYPE_QUEUEBUFFER: + psGEDLogBuf->attrs = GED_LOG_ATTR_QUEUEBUFFER; + break; + case GED_LOG_BUF_TYPE_QUEUEBUFFER_AUTO_INCREASE: + psGEDLogBuf->attrs = GED_LOG_ATTR_QUEUEBUFFER | GED_LOG_ATTR_AUTO_INCREASE; + break; + } + + psGEDLogBuf->i32MemorySize = i32MaxBufferSizeByte + sizeof(GED_LOG_BUF_LINE) * i32MaxLineCount; + psGEDLogBuf->pMemory = ged_alloc(psGEDLogBuf->i32MemorySize); + if (NULL == psGEDLogBuf->pMemory) + { + ged_free(psGEDLogBuf, sizeof(GED_LOG_BUF)); + GED_LOGE("ged: failed to allocate log buf!\n"); + return (GED_LOG_BUF_HANDLE)0; + } + + psGEDLogBuf->psLine = (GED_LOG_BUF_LINE *)psGEDLogBuf->pMemory; + psGEDLogBuf->pcBuffer = (char *)&psGEDLogBuf->psLine[i32MaxLineCount]; + psGEDLogBuf->i32LineCount = i32MaxLineCount; + psGEDLogBuf->i32BufferSize = i32MaxBufferSizeByte; + psGEDLogBuf->i32LineCurrent = 0; + psGEDLogBuf->i32BufferCurrent = 0; + + psGEDLogBuf->psEntry = NULL; + spin_lock_init(&psGEDLogBuf->sSpinLock); + psGEDLogBuf->acName[0] = '\0'; + psGEDLogBuf->acNodeName[0] = '\0'; + + /* Init Line */ + { + int i = 0; + for (i = 0; i < psGEDLogBuf->i32LineCount; ++i) + psGEDLogBuf->psLine[i].offset = -1; + } + + if (pszName) + { + snprintf(psGEDLogBuf->acName, GED_LOG_BUF_NAME_LENGTH, "%s", pszName); + } + + // Add into the global list + INIT_LIST_HEAD(&psGEDLogBuf->sList); + write_lock_bh(&gsGEDLogBufList.sLock); + list_add(&psGEDLogBuf->sList, &gsGEDLogBufList.sList_buf); + write_unlock_bh(&gsGEDLogBufList.sLock); + + if (pszNodeName) + { + int err; + snprintf(psGEDLogBuf->acNodeName, GED_LOG_BUF_NODE_NAME_LENGTH, "%s", pszNodeName); + err = ged_debugFS_create_entry( + psGEDLogBuf->acNodeName, + gpsGEDLogBufsDir, + &gsGEDLogBufReadOps, + ged_log_buf_write_entry, + psGEDLogBuf, + &psGEDLogBuf->psEntry); + + if (unlikely(err)) + { + GED_LOGE("ged: failed to create %s entry, err(%d)!\n", pszNodeName, err); + ged_log_buf_free(psGEDLogBuf->ui32HashNodeID); + return (GED_LOG_BUF_HANDLE)0; + } + } + + error = ged_hashtable_insert(ghHashTable, psGEDLogBuf, &psGEDLogBuf->ui32HashNodeID); + if (GED_OK != error) + { + GED_LOGE("ged: failed to insert into a hash table, err(%d)!\n", error); + ged_log_buf_free(psGEDLogBuf->ui32HashNodeID); + return (GED_LOG_BUF_HANDLE)0; + } + + GED_LOGI("ged_log_buf_alloc OK\n"); + + __ged_log_buf_check_get_early_list(psGEDLogBuf->ui32HashNodeID, pszName); + + return (GED_LOG_BUF_HANDLE)psGEDLogBuf->ui32HashNodeID; +} + +GED_ERROR ged_log_buf_resize( + GED_LOG_BUF_HANDLE hLogBuf, + int i32NewMaxLineCount, + int i32NewMaxBufferSizeByte) +{ + int i; + GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf); + int i32NewMemorySize, i32OldMemorySize; + void *pNewMemory, *pOldMemory; + GED_LOG_BUF_LINE *pi32NewLine; + char *pcNewBuffer; + + if ((NULL == psGEDLogBuf) || (i32NewMaxLineCount <= 0) || (i32NewMaxBufferSizeByte <= 0)) + { + return GED_ERROR_INVALID_PARAMS; + } + + i32NewMemorySize = i32NewMaxBufferSizeByte + sizeof(GED_LOG_BUF_LINE) * i32NewMaxLineCount; + pNewMemory = ged_alloc(i32NewMemorySize); + if (NULL == pNewMemory) + { + return GED_ERROR_OOM; + } + + spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + + pi32NewLine = (GED_LOG_BUF_LINE *)pNewMemory; + pcNewBuffer = (char *)&pi32NewLine[i32NewMaxLineCount]; + + memcpy(pi32NewLine, psGEDLogBuf->psLine, sizeof(GED_LOG_BUF_LINE) * min(i32NewMaxLineCount, psGEDLogBuf->i32LineCount)); + memcpy(pcNewBuffer, psGEDLogBuf->pcBuffer, min(i32NewMaxBufferSizeByte, psGEDLogBuf->i32BufferSize)); + + for (i = psGEDLogBuf->i32LineCount; i < i32NewMaxLineCount; ++i) + pi32NewLine[i].offset = -1; + + i32OldMemorySize = psGEDLogBuf->i32MemorySize; + pOldMemory = psGEDLogBuf->pMemory; + + psGEDLogBuf->i32MemorySize = i32NewMemorySize; + psGEDLogBuf->pMemory = pNewMemory; + psGEDLogBuf->psLine = pi32NewLine; + psGEDLogBuf->pcBuffer = pcNewBuffer; + psGEDLogBuf->i32LineCount = i32NewMaxLineCount; + psGEDLogBuf->i32BufferSize = i32NewMaxBufferSizeByte; + + if (psGEDLogBuf->i32BufferCurrent >= i32NewMaxBufferSizeByte) + psGEDLogBuf->i32BufferCurrent = i32NewMaxBufferSizeByte - 1; + pcNewBuffer[psGEDLogBuf->i32BufferCurrent] = 0; + + spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + ged_free(pOldMemory, i32OldMemorySize); + + return GED_OK; +} + +GED_ERROR ged_log_buf_ignore_lines(GED_LOG_BUF_HANDLE hLogBuf, int n) +{ + GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf); + + if (psGEDLogBuf && n > 0) + { + if (psGEDLogBuf->attrs & GED_LOG_ATTR_QUEUEBUFFER) + { + if (n >= psGEDLogBuf->i32LineCurrent) + { + /* reset all buffer */ + ged_log_buf_reset(hLogBuf); + } + else + { + int i; + int buf_offset; + int buf_size; + + spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + + buf_offset = psGEDLogBuf->psLine[n].offset; + buf_size = psGEDLogBuf->i32BufferCurrent - buf_offset; + + /* Move lines, update offset and update current */ + for (i = 0; n + i < psGEDLogBuf->i32LineCount; ++i) + { + psGEDLogBuf->psLine[i] = psGEDLogBuf->psLine[n + i]; + psGEDLogBuf->psLine[i].offset -= buf_offset; + } + psGEDLogBuf->i32LineCurrent -= n; + + /* Move buffers and update current */ + for (i = 0; i < buf_size; ++i) + psGEDLogBuf->pcBuffer[i] = psGEDLogBuf->pcBuffer[buf_offset + i]; + psGEDLogBuf->i32BufferCurrent = buf_size; + + spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + } + } + } + + return GED_OK; +} + +GED_LOG_BUF_HANDLE ged_log_buf_get(const char* pszName) +{ + struct list_head *psListEntry, *psListEntryTemp, *psList; + GED_LOG_BUF *psFound = NULL, *psLogBuf; + + if (!pszName) + { + return (GED_LOG_BUF_HANDLE)0; + } + + read_lock_bh(&gsGEDLogBufList.sLock); + + psList = &gsGEDLogBufList.sList_buf; + list_for_each_safe(psListEntry, psListEntryTemp, psList) + { + psLogBuf = list_entry(psListEntry, GED_LOG_BUF, sList); + if (0 == strcmp(psLogBuf->acName, pszName)) + { + psFound = psLogBuf; + break; + } + } + + read_unlock_bh(&gsGEDLogBufList.sLock); + + if (!psFound) + { + return (GED_LOG_BUF_HANDLE)0; + } + + return (GED_LOG_BUF_HANDLE)psFound->ui32HashNodeID; +} + +int ged_log_buf_get_early(const char* pszName, GED_LOG_BUF_HANDLE *callback_set_handle) +{ + int err = 0; + + if (NULL == pszName) + { + return GED_ERROR_INVALID_PARAMS; + } + + *callback_set_handle = ged_log_buf_get(pszName); + + if (0 == *callback_set_handle) + { + GED_LOG_LISTEN *psGEDLogListen; + + write_lock_bh(&gsGEDLogBufList.sLock); + + /* search again */ + { + struct list_head *psListEntry, *psListEntryTemp, *psList; + GED_LOG_BUF *psFound = NULL, *psLogBuf; + + psList = &gsGEDLogBufList.sList_buf; + list_for_each_safe(psListEntry, psListEntryTemp, psList) + { + psLogBuf = list_entry(psListEntry, GED_LOG_BUF, sList); + if (0 == strcmp(psLogBuf->acName, pszName)) + { + psFound = psLogBuf; + break; + } + } + + if (psFound) + { + *callback_set_handle = (GED_LOG_BUF_HANDLE)psFound->ui32HashNodeID; + goto exit_unlock; + } + } + + /* add to listen list */ + psGEDLogListen = (GED_LOG_LISTEN*)ged_alloc(sizeof(GED_LOG_LISTEN)); + if (NULL == psGEDLogListen) + { + err = GED_ERROR_OOM; + goto exit_unlock; + } + psGEDLogListen->pCBHnd = callback_set_handle; + snprintf(psGEDLogListen->acName, GED_LOG_BUF_NAME_LENGTH, "%s", pszName); + INIT_LIST_HEAD(&psGEDLogListen->sList); + list_add(&psGEDLogListen->sList, &gsGEDLogBufList.sList_listen); + +exit_unlock: + write_unlock_bh(&gsGEDLogBufList.sLock); + } + + return err; +} + +//----------------------------------------------------------------------------- +void ged_log_buf_free(GED_LOG_BUF_HANDLE hLogBuf) +{ + GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf); + if (psGEDLogBuf) + { + ged_hashtable_remove(ghHashTable, psGEDLogBuf->ui32HashNodeID); + + write_lock_bh(&gsGEDLogBufList.sLock); + list_del(&psGEDLogBuf->sList); + write_unlock_bh(&gsGEDLogBufList.sLock); + + if (psGEDLogBuf->psEntry) + { + ged_debugFS_remove_entry(psGEDLogBuf->psEntry); + } + + ged_free(psGEDLogBuf->pMemory, psGEDLogBuf->i32MemorySize); + ged_free(psGEDLogBuf, sizeof(GED_LOG_BUF)); + + GED_LOGI("ged_log_buf_free OK\n"); + } +} +//----------------------------------------------------------------------------- +GED_ERROR ged_log_buf_print(GED_LOG_BUF_HANDLE hLogBuf, const char *fmt, ...) +{ + va_list args; + GED_ERROR err; + GED_LOG_BUF *psGEDLogBuf; + + if (hLogBuf) + { + psGEDLogBuf = ged_log_buf_from_handle(hLogBuf); + + va_start(args, fmt); + err = __ged_log_buf_vprint(psGEDLogBuf, fmt, args, psGEDLogBuf->attrs); + va_end(args); + } + + return GED_OK; +} +GED_ERROR ged_log_buf_print2(GED_LOG_BUF_HANDLE hLogBuf, int i32LogAttrs, const char *fmt, ...) +{ + va_list args; + GED_ERROR err; + GED_LOG_BUF *psGEDLogBuf; + + if (hLogBuf) + { + psGEDLogBuf = ged_log_buf_from_handle(hLogBuf); + + /* clear reserved attrs */ + i32LogAttrs &= ~0xff; + + va_start(args, fmt); + err = __ged_log_buf_vprint(psGEDLogBuf, fmt, args, psGEDLogBuf->attrs | i32LogAttrs); + va_end(args); + } + + return GED_OK; +} +//----------------------------------------------------------------------------- +GED_ERROR ged_log_buf_reset(GED_LOG_BUF_HANDLE hLogBuf) +{ + GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf); + if (psGEDLogBuf) + { + int i; + spin_lock_irqsave(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + + psGEDLogBuf->i32LineCurrent = 0; + psGEDLogBuf->i32BufferCurrent = 0; + for (i = 0; i < psGEDLogBuf->i32LineCount; ++i) + { + psGEDLogBuf->psLine[i].offset = -1; + } + + spin_unlock_irqrestore(&psGEDLogBuf->sSpinLock, psGEDLogBuf->ui32IRQFlags); + } + + return GED_OK; +} + +//----------------------------------------------------------------------------- +// +// GED Log System +// +//----------------------------------------------------------------------------- +static ssize_t ged_log_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData) +{ +#define GED_LOG_CMD_SIZE 64 + char acBuffer[GED_LOG_CMD_SIZE]; + + int i32Value; + + if ((0 < uiCount) && (uiCount < GED_LOG_CMD_SIZE)) + { + if (0 == ged_copy_from_user(acBuffer, pszBuffer, uiCount)) + { + acBuffer[uiCount - 1] = '\0'; + if (strcmp(acBuffer, "reset") == 0) + { + struct list_head *psListEntry, *psListEntryTemp, *psList; + write_lock_bh(&gsGEDLogBufList.sLock); + psList = &gsGEDLogBufList.sList_buf; + list_for_each_safe(psListEntry, psListEntryTemp, psList) + { + GED_LOG_BUF* psGEDLogBuf = (GED_LOG_BUF*)list_entry(psListEntry, GED_LOG_BUF, sList); + ged_log_buf_reset(psGEDLogBuf->ui32HashNodeID); + } + write_unlock_bh(&gsGEDLogBufList.sLock); + } + else if (strcmp(acBuffer, "profile_dvfs_enable") == 0) + { + ged_profile_dvfs_enable(); + } + else if (strcmp(acBuffer, "profile_dvfs_disable") == 0) + { + ged_profile_dvfs_disable(); + } + else if (strcmp(acBuffer, "profile_dvfs_start") == 0) + { + ged_profile_dvfs_start(); + } + else if (strcmp(acBuffer, "profile_dvfs_stop") == 0) + { + ged_profile_dvfs_stop(); + } + else if (sscanf(acBuffer, "profile_dvfs_ignore_lines %d", &i32Value) == 1) + { + ged_profile_dvfs_ignore_lines(i32Value); + } + //else if (...) //for other commands + //{ + //} + } + } + + return uiCount; +} +//----------------------------------------------------------------------------- +static void* ged_log_seq_start(struct seq_file *psSeqFile, loff_t *puiPosition) +{ + struct list_head *psListEntry, *psListEntryTemp, *psList; + loff_t uiCurrentPosition = 0; + + read_lock_bh(&gsGEDLogBufList.sLock); + + psList = &gsGEDLogBufList.sList_buf; + list_for_each_safe(psListEntry, psListEntryTemp, psList) + { + GED_LOG_BUF* psGEDLogBuf = (GED_LOG_BUF*)list_entry(psListEntry, GED_LOG_BUF, sList); + if (psGEDLogBuf->acName[0] != '\0') + { + if (uiCurrentPosition == *puiPosition) + { + return psGEDLogBuf; + } + uiCurrentPosition ++; + } + } + + return NULL; +} +//----------------------------------------------------------------------------- +static void ged_log_seq_stop(struct seq_file *psSeqFile, void *pvData) +{ + read_unlock_bh(&gsGEDLogBufList.sLock); +} +//----------------------------------------------------------------------------- +static void* ged_log_seq_next(struct seq_file *psSeqFile, void *pvData, loff_t *puiPosition) +{ + struct list_head *psListEntry, *psListEntryTemp, *psList; + loff_t uiCurrentPosition = 0; + + (*puiPosition)++; + + psList = &gsGEDLogBufList.sList_buf; + list_for_each_safe(psListEntry, psListEntryTemp, psList) + { + GED_LOG_BUF* psGEDLogBuf = (GED_LOG_BUF*)list_entry(psListEntry, GED_LOG_BUF, sList); + if (psGEDLogBuf->acName[0] != '\0') + { + if (uiCurrentPosition == *puiPosition) + { + return psGEDLogBuf; + } + uiCurrentPosition ++; + } + } + + return NULL; +} +//----------------------------------------------------------------------------- +static struct seq_operations gsGEDLogReadOps = +{ + .start = ged_log_seq_start, + .stop = ged_log_seq_stop, + .next = ged_log_seq_next, + .show = ged_log_buf_seq_show, +}; +//----------------------------------------------------------------------------- +GED_ERROR ged_log_system_init(void) +{ + GED_ERROR err = GED_OK; + + err = ged_debugFS_create_entry( + "gedlog", + NULL, + &gsGEDLogReadOps, + ged_log_write_entry, + NULL, + &gpsGEDLogEntry); + + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to create gedlog entry!\n"); + goto ERROR; + } + + err = ged_debugFS_create_entry_dir( + "logbufs", + NULL, + &gpsGEDLogBufsDir); + + if (unlikely(err != GED_OK)) + { + err = GED_ERROR_FAIL; + GED_LOGE("ged: failed to create logbufs dir!\n"); + goto ERROR; + } + + ghHashTable = ged_hashtable_create(5); + if (!ghHashTable) + { + err = GED_ERROR_OOM; + GED_LOGE("ged: failed to create a hash table!\n"); + goto ERROR; + } + + return err; + +ERROR: + + ged_log_system_exit(); + + return err; +} +//----------------------------------------------------------------------------- +void ged_log_system_exit(void) +{ + ged_hashtable_destroy(ghHashTable); + + ged_debugFS_remove_entry(gpsGEDLogEntry); +} +//----------------------------------------------------------------------------- +int ged_log_buf_write(GED_LOG_BUF_HANDLE hLogBuf, const char __user *pszBuffer, int i32Count) +{ + GED_LOG_BUF *psGEDLogBuf = ged_log_buf_from_handle(hLogBuf); + return __ged_log_buf_write(psGEDLogBuf, pszBuffer, i32Count); +} + +EXPORT_SYMBOL(ged_log_buf_alloc); +EXPORT_SYMBOL(ged_log_buf_reset); +EXPORT_SYMBOL(ged_log_buf_get); +EXPORT_SYMBOL(ged_log_buf_get_early); +EXPORT_SYMBOL(ged_log_buf_free); +EXPORT_SYMBOL(ged_log_buf_print); +EXPORT_SYMBOL(ged_log_buf_print2); diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_main.c b/drivers/misc/mediatek/gpu/ged/src/ged_main.c new file mode 100644 index 000000000..eff199d18 --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_main.c @@ -0,0 +1,338 @@ +/* + * (C) Copyright 2010 + * MediaTek <www.MediaTek.com> + * + * MTK GPU Extension Device + * + */ + +#include <linux/cdev.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/hardirq.h> +#include <linux/init.h> +#include <linux/kallsyms.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/poll.h> +#include <linux/proc_fs.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> +#include <linux/disp_assert_layer.h> +#include <mach/system.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/semaphore.h> +#include <linux/workqueue.h> +#include <linux/kthread.h> +#include <linux/aee.h> + +#include "ged_debugFS.h" +#include "ged_log.h" +#include "ged_hal.h" +#include "ged_bridge.h" +#include "ged_profile_dvfs.h" +#include "ged_monitor_3D_fence.h" + +#define GED_DRIVER_DEVICE_NAME "ged" + +#define GED_IOCTL_PARAM_BUF_SIZE 0x3000 //12KB + +#ifdef GED_DEBUG +#define GED_LOG_BUF_COMMON_FENCE "FENCE" +static GED_LOG_BUF_HANDLE ghLogBuf_FENCE = 0; +#define GED_LOG_BUF_COMMON_GLES "GLES" +static GED_LOG_BUF_HANDLE ghLogBuf_GLES = 0; +GED_LOG_BUF_HANDLE ghLogBuf_GED = 0; +#endif + +static void* gvIOCTLParamBuf = NULL; + +/****************************************************************************** + * GED File operations + *****************************************************************************/ +static int ged_open(struct inode *inode, struct file *filp) +{ + GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); + return 0; +} + +static int ged_release(struct inode *inode, struct file *filp) +{ + GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); + return 0; +} + +static unsigned int ged_poll(struct file *file, struct poll_table_struct *ptable) +{ + return 0; +} + +static ssize_t ged_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + return 0; +} + +static ssize_t ged_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + return 0; +} + +static long ged_dispatch(GED_BRIDGE_PACKAGE *psBridgePackageKM) +{ + int ret = -EFAULT; + void *pvInt, *pvOut; + typedef int (ged_bridge_func_type)(void*, void*); + ged_bridge_func_type* pFunc = NULL; + + if ((psBridgePackageKM->i32InBufferSize >=0) && (psBridgePackageKM->i32OutBufferSize >=0) && + (psBridgePackageKM->i32InBufferSize + psBridgePackageKM->i32OutBufferSize < GED_IOCTL_PARAM_BUF_SIZE)) + { + pvInt = gvIOCTLParamBuf; + pvOut = (void*)((char*)pvInt + (uintptr_t)psBridgePackageKM->i32InBufferSize); + if (psBridgePackageKM->i32InBufferSize > 0) + { + if (0 != ged_copy_from_user(pvInt, psBridgePackageKM->pvParamIn, psBridgePackageKM->i32InBufferSize)) + { + GED_LOGE("ged_copy_from_user fail\n"); + return ret; + } + } + + // we will change the below switch into a function pointer mapping table in the future + switch(GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID)) + { + case GED_BRIDGE_COMMAND_LOG_BUF_GET: + pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_get; + break; + case GED_BRIDGE_COMMAND_LOG_BUF_WRITE: + pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_write; + break; + case GED_BRIDGE_COMMAND_LOG_BUF_RESET: + pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_reset; + break; + case GED_BRIDGE_COMMAND_BOOST_GPU_FREQ: + pFunc = (ged_bridge_func_type*)ged_bridge_boost_gpu_freq; + break; + case GED_BRIDGE_COMMAND_MONITOR_3D_FENCE: + pFunc = (ged_bridge_func_type*)ged_bridge_monitor_3D_fence; + break; + default: + GED_LOGE("Unknown Bridge ID: %u\n", GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID)); + break; + } + + if (pFunc) + { + ret = pFunc(pvInt, pvOut); + } + + if (psBridgePackageKM->i32OutBufferSize > 0) + { + if (0 != ged_copy_to_user(psBridgePackageKM->pvParamOut, pvOut, psBridgePackageKM->i32OutBufferSize)) + { + return ret; + } + } + } + + return ret; +} + +DEFINE_SEMAPHORE(ged_dal_sem); + +static long ged_ioctl(struct file *pFile, unsigned int ioctlCmd, unsigned long arg) +{ + int ret = -EFAULT; + GED_BRIDGE_PACKAGE *psBridgePackageKM, *psBridgePackageUM = (GED_BRIDGE_PACKAGE*)arg; + GED_BRIDGE_PACKAGE sBridgePackageKM; + + if (down_interruptible(&ged_dal_sem) < 0) + { + GED_LOGE("Fail to down ged_dal_sem\n"); + return -ERESTARTSYS; + } + + psBridgePackageKM = &sBridgePackageKM; + if (0 != ged_copy_from_user(psBridgePackageKM, psBridgePackageUM, sizeof(GED_BRIDGE_PACKAGE))) + { + GED_LOGE("Fail to ged_copy_from_user\n"); + goto unlock_and_return; + } + + ret = ged_dispatch(psBridgePackageKM); + +unlock_and_return: + up(&ged_dal_sem); + + return ret; +} + +#ifdef CONFIG_COMPAT +static long ged_ioctl_compat(struct file *pFile, unsigned int ioctlCmd, unsigned long arg) +{ + typedef struct GED_BRIDGE_PACKAGE_32_TAG + { + unsigned int ui32FunctionID; + int i32Size; + unsigned int ui32ParamIn; + int i32InBufferSize; + unsigned int ui32ParamOut; + int i32OutBufferSize; + } GED_BRIDGE_PACKAGE_32; + + int ret = -EFAULT; + GED_BRIDGE_PACKAGE sBridgePackageKM64; + GED_BRIDGE_PACKAGE_32 sBridgePackageKM32; + GED_BRIDGE_PACKAGE_32 *psBridgePackageKM32 = &sBridgePackageKM32; + GED_BRIDGE_PACKAGE_32 *psBridgePackageUM32 = (GED_BRIDGE_PACKAGE_32*)arg; + + if (down_interruptible(&ged_dal_sem) < 0) + { + GED_LOGE("Fail to down ged_dal_sem\n"); + return -ERESTARTSYS; + } + + if (0 != ged_copy_from_user(psBridgePackageKM32, psBridgePackageUM32, sizeof(GED_BRIDGE_PACKAGE_32))) + { + GED_LOGE("Fail to ged_copy_from_user\n"); + goto unlock_and_return; + } + + sBridgePackageKM64.ui32FunctionID = psBridgePackageKM32->ui32FunctionID; + sBridgePackageKM64.i32Size = sizeof(GED_BRIDGE_PACKAGE); + sBridgePackageKM64.pvParamIn = (void*) ((size_t) psBridgePackageKM32->ui32ParamIn); + sBridgePackageKM64.pvParamOut = (void*) ((size_t) psBridgePackageKM32->ui32ParamOut); + sBridgePackageKM64.i32InBufferSize = psBridgePackageKM32->i32InBufferSize; + sBridgePackageKM64.i32OutBufferSize = psBridgePackageKM32->i32OutBufferSize; + + ret = ged_dispatch(&sBridgePackageKM64); + +unlock_and_return: + up(&ged_dal_sem); + + return ret; +} +#endif + +/****************************************************************************** + * Module related + *****************************************************************************/ + +static struct file_operations ged_fops = { + .owner = THIS_MODULE, + .open = ged_open, + .release = ged_release, + .poll = ged_poll, + .read = ged_read, + .write = ged_write, + .unlocked_ioctl = ged_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ged_ioctl_compat, +#endif +}; + +#if 0 +static struct miscdevice ged_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "ged", + .fops = &ged_fops, +}; +#endif + +static void ged_exit(void) +{ +#ifdef GED_DEBUG + ged_log_buf_free(ghLogBuf_GED); + ghLogBuf_GED = 0; + ged_log_buf_free(ghLogBuf_GLES); + ghLogBuf_GLES = 0; + ged_log_buf_free(ghLogBuf_FENCE); + ghLogBuf_FENCE = 0; +#endif + + ged_profile_dvfs_exit(); + + ged_hal_exit(); + + ged_log_system_exit(); + + ged_debugFS_exit(); + + remove_proc_entry(GED_DRIVER_DEVICE_NAME, NULL); + + if (gvIOCTLParamBuf) + { + vfree(gvIOCTLParamBuf); + gvIOCTLParamBuf = NULL; + } +} + +static int ged_init(void) +{ + GED_ERROR err = GED_ERROR_FAIL; + + gvIOCTLParamBuf = vmalloc(GED_IOCTL_PARAM_BUF_SIZE); + if (NULL == gvIOCTLParamBuf) + { + err = GED_ERROR_OOM; + goto ERROR; + } + + if (NULL == proc_create(GED_DRIVER_DEVICE_NAME, 0644, NULL, &ged_fops)) + { + err = GED_ERROR_FAIL; + GED_LOGE("ged: failed to register ged proc entry!\n"); + goto ERROR; + } + + err = ged_debugFS_init(); + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to init debug FS!\n"); + goto ERROR; + } + + err = ged_log_system_init(); + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to create gedlog entry!\n"); + goto ERROR; + } + + err = ged_hal_init(); + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to create hal entry!\n"); + goto ERROR; + } + + err = ged_profile_dvfs_init(); + if (unlikely(err != GED_OK)) + { + GED_LOGE("ged: failed to init profile dvfs!\n"); + goto ERROR; + } + +#ifdef GED_DEBUG + ghLogBuf_FENCE = ged_log_buf_alloc(256, 128 * 256, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_FENCE, NULL); + ghLogBuf_GLES = ged_log_buf_alloc(160, 128 * 160, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_GLES, NULL); + ghLogBuf_GED = ged_log_buf_alloc(32, 64 * 32, GED_LOG_BUF_TYPE_RINGBUFFER, "GED internal", NULL); +#endif + + return 0; + +ERROR: + ged_exit(); + + return -EFAULT; +} + +module_init(ged_init); +module_exit(ged_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek GED Driver"); +MODULE_AUTHOR("MediaTek Inc."); diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c b/drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c new file mode 100644 index 000000000..b953a2b44 --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_monitor_3D_fence.c @@ -0,0 +1,141 @@ +#include <linux/version.h> +#include <linux/workqueue.h> +#include <linux/sched.h> +#include <asm/atomic.h> +#include <linux/module.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)) +#include <linux/sync.h> +#else +#include <../drivers/staging/android/sync.h> +#endif + +#include <linux/mtk_gpu_utility.h> +#include <trace/events/gpu.h> +#include "ged_monitor_3D_fence.h" +#include "ged_log.h" +#include "ged_base.h" + +static atomic_t g_i32Count = ATOMIC_INIT(0); +static unsigned int ged_monitor_3D_fence_debug = 0; +static unsigned int ged_monitor_3D_fence_disable = 0; +static unsigned int ged_monitor_3D_fence_systrace = 0; + +#ifdef GED_DEBUG_MONITOR_3D_FENCE +extern GED_LOG_BUF_HANDLE ghLogBuf_GED; +#endif + +typedef struct GED_MONITOR_3D_FENCE_TAG +{ + struct sync_fence_waiter sSyncWaiter; + struct work_struct sWork; + struct sync_fence* psSyncFence; +} GED_MONITOR_3D_FENCE; + +static void ged_sync_cb(struct sync_fence *fence, struct sync_fence_waiter *waiter) +{ + GED_MONITOR_3D_FENCE *psMonitor; + psMonitor = GED_CONTAINER_OF(waiter, GED_MONITOR_3D_FENCE, sSyncWaiter); + schedule_work(&psMonitor->sWork); +} + +static void ged_monitor_3D_fence_work_cb(struct work_struct *psWork) +{ + GED_MONITOR_3D_FENCE *psMonitor; + + if (atomic_sub_return(1, &g_i32Count) < 1) + { + if (0 == ged_monitor_3D_fence_disable) + { + //unsigned int uiFreqLevelID; + //if (mtk_get_bottom_gpu_freq(&uiFreqLevelID)) + { + //if (uiFreqLevelID > 0) + { + mtk_set_bottom_gpu_freq(0); +#ifdef CONFIG_GPU_TRACEPOINTS + if (ged_monitor_3D_fence_systrace) + { + unsigned long long t = cpu_clock(smp_processor_id()); + trace_gpu_sched_switch("Smart Boost", t, 0, 0, 1); + } +#endif + } + } + } + } + + if (ged_monitor_3D_fence_debug > 0) + { + GED_LOGI("[-]3D fences count = %d\n", atomic_read(&g_i32Count)); + } + + psMonitor = GED_CONTAINER_OF(psWork, GED_MONITOR_3D_FENCE, sWork); + sync_fence_put(psMonitor->psSyncFence); + ged_free(psMonitor, sizeof(GED_MONITOR_3D_FENCE)); +} + +GED_ERROR ged_monitor_3D_fence_add(int fence_fd) +{ + int err; + GED_MONITOR_3D_FENCE* psMonitor; + + psMonitor = (GED_MONITOR_3D_FENCE*)ged_alloc(sizeof(GED_MONITOR_3D_FENCE)); + if (!psMonitor) + { + return GED_ERROR_OOM; + } + + sync_fence_waiter_init(&psMonitor->sSyncWaiter, ged_sync_cb); + INIT_WORK(&psMonitor->sWork, ged_monitor_3D_fence_work_cb); + psMonitor->psSyncFence = sync_fence_fdget(fence_fd); + if (NULL == psMonitor->psSyncFence) + { + ged_free(psMonitor, sizeof(GED_MONITOR_3D_FENCE)); + return GED_ERROR_INVALID_PARAMS; + } + + err = sync_fence_wait_async(psMonitor->psSyncFence, &psMonitor->sSyncWaiter); + + if ((1 == err) || (0 > err)) + { + sync_fence_put(psMonitor->psSyncFence); + ged_free(psMonitor, sizeof(GED_MONITOR_3D_FENCE)); + } + else if (0 == err) + { + int iCount = atomic_add_return(1, &g_i32Count); + if (iCount > 1) + { + if (0 == ged_monitor_3D_fence_disable) + { + //unsigned int uiFreqLevelID; + //if (mtk_get_bottom_gpu_freq(&uiFreqLevelID)) + { + //if (uiFreqLevelID != 4) + { +#ifdef CONFIG_GPU_TRACEPOINTS + if (ged_monitor_3D_fence_systrace) + { + unsigned long long t = cpu_clock(smp_processor_id()); + trace_gpu_sched_switch("Smart Boost", t, 1, 0, 1); + } +#endif + mtk_set_bottom_gpu_freq(4); + } + } + } + } + } + + if (ged_monitor_3D_fence_debug > 0) + { + GED_LOGI("[+]3D fences count = %d\n", atomic_read(&g_i32Count)); + } + + return GED_OK; +} + +module_param(ged_monitor_3D_fence_debug, uint, 0644); +module_param(ged_monitor_3D_fence_disable, uint, 0644); +module_param(ged_monitor_3D_fence_systrace, uint, 0644); diff --git a/drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c b/drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c new file mode 100644 index 000000000..05cf7d7c4 --- /dev/null +++ b/drivers/misc/mediatek/gpu/ged/src/ged_profile_dvfs.c @@ -0,0 +1,190 @@ +#include <linux/slab.h> +#include <linux/sched.h> +#include "ged_base.h" +#include "ged_log.h" +#include "ged_profile_dvfs.h" + +static GED_LOG_BUF_HANDLE ghLogBuf = 0; +static struct mutex gsMutex; +static GED_BOOL gbAllowRecord = GED_FALSE; + +GED_ERROR ged_profile_dvfs_init(void) +{ + mutex_init(&gsMutex); + +#if 0 + ghLogBuf = ged_log_buf_alloc(320, 64 * 320, GED_LOG_BUF_TYPE_QUEUEBUFFER_AUTO_INCREASE, NULL, "profile_dvfs"); +#endif + + return GED_OK; +} + +GED_ERROR ged_profile_dvfs_enable(void) +{ + GED_ERROR ret; + + mutex_lock(&gsMutex); + + if (NULL == ghLogBuf) + { + ghLogBuf = ged_log_buf_alloc(320, 64 * 320, GED_LOG_BUF_TYPE_QUEUEBUFFER_AUTO_INCREASE, NULL, "profile_dvfs"); + } + + ret = ghLogBuf ? GED_OK : GED_ERROR_FAIL; + + mutex_unlock(&gsMutex); + + return ret; +} + +void ged_profile_dvfs_disable(void) +{ + mutex_lock(&gsMutex); + + if (NULL != ghLogBuf) + { + ged_log_buf_free(ghLogBuf); + ghLogBuf = NULL; + } + + mutex_unlock(&gsMutex); +} + +void ged_profile_dvfs_start(void) +{ + gbAllowRecord = GED_TRUE; +} + +void ged_profile_dvfs_stop(void) +{ + gbAllowRecord = GED_FALSE; +} + +void ged_profile_dvfs_ignore_lines(int i32LineCount) +{ + mutex_lock(&gsMutex); + + if (ghLogBuf) + { + ged_log_buf_ignore_lines(ghLogBuf, i32LineCount); + } + + mutex_unlock(&gsMutex); +} + +void ged_profile_dvfs_exit(void) +{ + ged_profile_dvfs_disable(); +} + +void ged_profile_dvfs_record_freq_volt(unsigned int ui32Frequency, unsigned int ui32Voltage) +{ + mutex_lock(&gsMutex); + + if (ghLogBuf && gbAllowRecord) + { + /* copy & modify from ./kernel/printk.c */ + unsigned long long t; + unsigned long nanosec_rem; + + t = cpu_clock(smp_processor_id()); + nanosec_rem = do_div(t, 1000000000) / 1000; + + ged_log_buf_print(ghLogBuf, "%5lu.%06lu,freq_volt,%u,%u", (unsigned long) t, nanosec_rem, ui32Frequency, ui32Voltage); + } + mutex_unlock(&gsMutex); +} + +void ged_profile_dvfs_record_temp(int i32Temp) +{ + mutex_lock(&gsMutex); + + if (ghLogBuf && gbAllowRecord) + { + /* copy & modify from ./kernel/printk.c */ + unsigned long long t; + unsigned long nanosec_rem; + + t = cpu_clock(smp_processor_id()); + nanosec_rem = do_div(t, 1000000000) / 1000; + + ged_log_buf_print(ghLogBuf, "%5lu.%06lu,temp,%d", (unsigned long) t, nanosec_rem, i32Temp); + } + mutex_unlock(&gsMutex); + +} + +void ged_profile_dvfs_record_thermal_limit(unsigned int ui32FreqLimit) +{ + mutex_lock(&gsMutex); + + if (ghLogBuf && gbAllowRecord) + { + /* copy & modify from ./kernel/printk.c */ + unsigned long long t; + unsigned long nanosec_rem; + + t = cpu_clock(smp_processor_id()); + nanosec_rem = do_div(t, 1000000000) / 1000; + + ged_log_buf_print(ghLogBuf, "%5lu.%06lu,thermal_limit,%u", (unsigned long) t, nanosec_rem, ui32FreqLimit); + } + mutex_unlock(&gsMutex); +} + +void ged_profile_dvfs_record_gpu_loading(unsigned int ui32GpuLoading) +{ + mutex_lock(&gsMutex); + + if (ghLogBuf && gbAllowRecord) + { + /* copy & modify from ./kernel/printk.c */ + unsigned long long t; + unsigned long nanosec_rem; + + t = cpu_clock(smp_processor_id()); + nanosec_rem = do_div(t, 1000000000) / 1000; + + ged_log_buf_print(ghLogBuf, "%5lu.%06lu,gpu_load,%u", (unsigned long) t, nanosec_rem, ui32GpuLoading); + } + + mutex_unlock(&gsMutex); +} + +void ged_profile_dvfs_record_clock_on(void) +{ + mutex_lock(&gsMutex); + + if (ghLogBuf && gbAllowRecord) + { + /* copy & modify from ./kernel/printk.c */ + unsigned long long t; + unsigned long nanosec_rem; + + t = cpu_clock(smp_processor_id()); + nanosec_rem = do_div(t, 1000000000) / 1000; + + ged_log_buf_print(ghLogBuf, "%5lu.%06lu,gpu_clock,1", (unsigned long) t, nanosec_rem); + } + + mutex_unlock(&gsMutex); +} + +void ged_profile_dvfs_record_clock_off(void) +{ + mutex_lock(&gsMutex); + + if (ghLogBuf && gbAllowRecord) + { + /* copy & modify from ./kernel/printk.c */ + unsigned long long t; + unsigned long nanosec_rem; + + t = cpu_clock(smp_processor_id()); + nanosec_rem = do_div(t, 1000000000) / 1000; + + ged_log_buf_print(ghLogBuf, "%5lu.%06lu,gpu_clock,0", (unsigned long) t, nanosec_rem); + } + + mutex_unlock(&gsMutex); +} |
