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; }
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; }
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_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; }
static void ged_dvfs_custom_ceiling_gpu_freq(unsigned int ui32FreqLevel) { unsigned int ui32MaxLevel; if (gpu_debug_enable) { GED_LOGE("%s: freq = %d", __func__,ui32FreqLevel); } ui32MaxLevel = mt_gpufreq_get_dvfs_table_num() - 1; if (ui32MaxLevel < ui32FreqLevel) { ui32FreqLevel = ui32MaxLevel; } mutex_lock(&gsDVFSLock); // 0 => The highest frequency // table_num - 1 => The lowest frequency g_cust_upbound_freq_id = ui32MaxLevel - ui32FreqLevel; gpu_cust_upbound_freq = mt_gpufreq_get_freq_by_idx(g_cust_upbound_freq_id); if (g_cust_upbound_freq_id > mt_gpufreq_get_cur_freq_index()) { ged_dvfs_gpu_freq_commit(g_cust_upbound_freq_id, GED_DVFS_CUSTOM_CEIL_COMMIT); } mutex_unlock(&gsDVFSLock); }
static void ged_dvfs_set_bottom_gpu_freq(unsigned int ui32FreqLevel) { unsigned int ui32MaxLevel; if (gpu_debug_enable) { GED_LOGE("%s: freq = %d", __func__,ui32FreqLevel); } ui32MaxLevel = mt_gpufreq_get_dvfs_table_num() - 1; if (ui32MaxLevel < ui32FreqLevel) { ui32FreqLevel = ui32MaxLevel; } mutex_lock(&gsDVFSLock); // 0 => The highest frequency // table_num - 1 => The lowest frequency g_bottom_freq_id = ui32MaxLevel - ui32FreqLevel; gpu_bottom_freq = mt_gpufreq_get_freq_by_idx(g_bottom_freq_id); //if current id is larger, ie lower freq, we need to reflect immedately if(g_bottom_freq_id < mt_gpufreq_get_cur_freq_index()) ged_dvfs_gpu_freq_commit(g_bottom_freq_id, GED_DVFS_SET_BOTTOM_COMMIT); mutex_unlock(&gsDVFSLock); }
void ged_dvfs_boost_gpu_freq(void) { if (gpu_debug_enable) { GED_LOGE("%s", __func__); } ged_dvfs_freq_input_boostCB(0); }
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; }
void ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_SWITCH_CMD eEvent, bool bSwitch) { unsigned int ui32BeforeSwitchInterpret; unsigned int ui32BeforeDebugInterpret; mutex_lock(&gsVSyncOffsetLock); ui32BeforeSwitchInterpret = g_ui32EventStatus; ui32BeforeDebugInterpret = g_ui32EventDebugStatus; switch(eEvent) { case GED_DVFS_VSYNC_OFFSET_FORCE_ON: g_ui32EventDebugStatus |= GED_EVENT_FORCE_ON; g_ui32EventDebugStatus &= (~GED_EVENT_FORCE_OFF); break; case GED_DVFS_VSYNC_OFFSET_FORCE_OFF: g_ui32EventDebugStatus |= GED_EVENT_FORCE_OFF; g_ui32EventDebugStatus &= (~GED_EVENT_FORCE_ON); break; case GED_DVFS_VSYNC_OFFSET_DEBUG_CLEAR_EVENT: g_ui32EventDebugStatus &= (~GED_EVENT_FORCE_ON); g_ui32EventDebugStatus &= (~GED_EVENT_FORCE_OFF); break; case GED_DVFS_VSYNC_OFFSET_TOUCH_EVENT: if(GED_TRUE==bSwitch) // touch boost ged_dvfs_boost_gpu_freq(); (bSwitch)? (g_ui32EventStatus|=GED_EVENT_TOUCH): (g_ui32EventStatus&= (~GED_EVENT_TOUCH)); break; case GED_DVFS_VSYNC_OFFSET_THERMAL_EVENT: (bSwitch)? (g_ui32EventStatus|=GED_EVENT_THERMAL): (g_ui32EventStatus&= (~GED_EVENT_THERMAL)); break; case GED_DVFS_VSYNC_OFFSET_WFD_EVENT: (bSwitch)? (g_ui32EventStatus|=GED_EVENT_WFD): (g_ui32EventStatus&= (~GED_EVENT_WFD)); break; case GED_DVFS_VSYNC_OFFSET_MHL_EVENT: (bSwitch)? (g_ui32EventStatus|=GED_EVENT_MHL): (g_ui32EventStatus&= (~GED_EVENT_MHL)); break; case GED_DVFS_VSYNC_OFFSET_GAS_EVENT: (bSwitch)? (g_ui32EventStatus|=GED_EVENT_GAS): (g_ui32EventStatus&= (~GED_EVENT_GAS)); break; default: GED_LOGE("%s: not acceptable event:%u \n", __func__, eEvent); goto CHECK_OUT; } if(ui32BeforeSwitchInterpret != g_ui32EventStatus || ui32BeforeDebugInterpret != g_ui32EventDebugStatus || g_ui32EventDebugStatus&GED_EVENT_NOT_SYNC) { ged_dvfs_probe_signal(GED_DVFS_VSYNC_OFFSET_SIGNAL_EVENT); } CHECK_OUT: mutex_unlock(&gsVSyncOffsetLock); }
//ged_dvfs_vsync_offset_level_set static ssize_t ged_vsync_offset_level_write_entry( const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData) { #define GED_HAL_DEBUGFS_SIZE 64 #define NUM_TOKEN 2 /* * This proc node accept only: [CMD] [NUM] * for ex: "touch 1" * */ char acBuffer[GED_HAL_DEBUGFS_SIZE]; int aint32Indx[NUM_TOKEN]; char* pcCMD; char* pcValue; int i; int i32VsyncOffsetLevel; int ret; if (!((0 < uiCount) && (uiCount < GED_HAL_DEBUGFS_SIZE - 1))) return 0; if (ged_copy_from_user(acBuffer, pszBuffer, uiCount)) return 0; acBuffer[uiCount] = '\n'; acBuffer[uiCount+1] = 0; i=tokenizer(acBuffer, uiCount, aint32Indx, NUM_TOKEN); GED_LOGE("i=%d",i); if(i==NUM_TOKEN) { pcCMD = acBuffer+aint32Indx[0]; pcValue = acBuffer+aint32Indx[1]; if(strcmp(pcCMD,"set_vsync_offset")==0) { ret = kstrtoint(pcValue, 0, &i32VsyncOffsetLevel); ged_dvfs_vsync_offset_level_set(i32VsyncOffsetLevel); } } 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; }
//----------------------------------------------------------------------------- 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; } /* Enable/Disable the vsync offset */ err = ged_debugFS_create_entry( "event_notify", gpsHALDir, &gsVsync_offset_enableReadOps, ged_vsync_offset_enable_write_entry, NULL, &gpsVsyncOffsetEnableEntry); /* Control the vsync offset level */ err = ged_debugFS_create_entry( "vsync_offset_level", gpsHALDir, &gsVsync_offset_levelReadOps, ged_vsync_offset_level_write_entry, NULL, &gpsVsyncOffsetLevelEntry); /* Control the dvfs policy threshold level */ err = ged_debugFS_create_entry( "custom_dvfs_mode", gpsHALDir, &gsDvfs_tuning_mode_ReadOps, ged_dvfs_tuning_mode_write_entry, NULL, &gpsDvfsTuningModeEntry); /* Get current GPU freq */ err = ged_debugFS_create_entry( "current_freqency", gpsHALDir, &gsDvfs_cur_freq_ReadOps, NULL, NULL, &gpsDvfsCurFreqEntry); /* Get previous GPU freq */ err = ged_debugFS_create_entry( "previous_freqency", gpsHALDir, &gsDvfs_pre_freq_ReadOps, NULL, NULL, &gpsDvfsPreFreqEntry); /* Get GPU Utilization */ err = ged_debugFS_create_entry( "gpu_utilization", gpsHALDir, &gsDvfs_gpu_util_ReadOps, NULL, NULL, &gpsDvfsGpuUtilizationEntry); /* Get FPS upper bound */ err = ged_debugFS_create_entry( "fps_upper_bound", gpsHALDir, &gs_fps_ub_read_ops, ged_fps_ub_write, NULL, &gpsFpsUpperBoundEntry ); if (unlikely(err != GED_OK)) { GED_LOGE("ged: failed to create vsync_offset_level entry!\n"); goto ERROR; } return err; ERROR: ged_hal_exit(); return err; }
static ssize_t ged_vsync_offset_enable_write_entry(const char __user *pszBuffer, size_t uiCount, loff_t uiPosition, void *pvData) { #define GED_HAL_DEBUGFS_SIZE 64 #define NUM_TOKEN 2 /* * This proc node accept only: [CMD] [NUM] * for ex: "touch 1" * */ char acBuffer[GED_HAL_DEBUGFS_SIZE]; int aint32Indx[NUM_TOKEN]; char* pcCMD; char* pcValue; int i; if ((0 < uiCount) && (uiCount < GED_HAL_DEBUGFS_SIZE)) { if (0 == ged_copy_from_user(acBuffer, pszBuffer, uiCount)) { acBuffer[uiCount] = '\0'; i=tokenizer(acBuffer, uiCount, aint32Indx, NUM_TOKEN); if(i==NUM_TOKEN) { pcCMD = acBuffer+aint32Indx[0]; pcValue = acBuffer+aint32Indx[1]; #ifdef ENABLE_COMMON_DVFS if(strcmp(pcCMD,"touch_down")==0) { if ( (*pcValue)=='1'|| (*pcValue) =='0') { if( (*pcValue) -'0'==0) // touch up ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_TOUCH_EVENT , false); else // touch down ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_TOUCH_EVENT , true); } } else if(strcmp(pcCMD,"enable_WFD")==0) { if ( (*pcValue) =='1'|| (*pcValue) =='0') { if( (*pcValue) -'0'==0) // WFD turn-off ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_WFD_EVENT , false); else // WFD turn-on ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_WFD_EVENT , true); } } else #endif if(strcmp(pcCMD,"enable_debug")==0) { if ( (*pcValue) =='1'|| (*pcValue) =='0'||(*pcValue) =='2') { if( (*pcValue) -'0'==1) // force off { ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_FORCE_OFF , true); bForce = GED_FALSE; } else if( (*pcValue) -'0'==2) // force on { ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_FORCE_ON , true); bForce = GED_TRUE; } else // turn-off debug ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_DEBUG_CLEAR_EVENT , true); } } else if(strcmp(pcCMD, "gas") == 0) { if ( (*pcValue) =='1'|| (*pcValue) =='0') { if( (*pcValue) -'0'==0) ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_GAS_EVENT, false); else ged_dvfs_vsync_offset_event_switch(GED_DVFS_VSYNC_OFFSET_GAS_EVENT, true); } } else { GED_LOGE("unknow command:%s %c",pcCMD,*pcValue); } } } } return uiCount; }
void ged_dvfs_run(unsigned long t, long phase, unsigned long ul3DFenceDoneTime) { bool bError; //ged_profile_dvfs_record_SW_vsync(t, phase, ul3DFenceDoneTime); mutex_lock(&gsDVFSLock); //gpu_pre_loading = gpu_loading; if (0 == gpu_dvfs_enable) { gpu_power = 0; gpu_loading = 0; gpu_block= 0; gpu_idle = 0; goto EXIT_ged_dvfs_run; } // SKIP for keeping boost freq if(g_dvfs_skip_round>0) { g_dvfs_skip_round--; goto EXIT_ged_dvfs_run; } if (g_iSkipCount > 0) { gpu_power = 0; gpu_loading = 0; gpu_block= 0; gpu_idle = 0; g_iSkipCount -= 1; } else { g_ulPreCalResetTS_us = g_ulCalResetTS_us; g_ulCalResetTS_us = t; bError=ged_dvfs_cal_gpu_utilization(&gpu_loading, &gpu_block, &gpu_idle); #ifdef GED_DVFS_UM_CAL if(GED_DVFS_FALLBACK==phase) // timer-based DVFS use only #endif { if (ged_dvfs_policy(gpu_loading, &g_ui32FreqIDFromPolicy, t, phase, ul3DFenceDoneTime, false)) { g_computed_freq_id = g_ui32FreqIDFromPolicy; ged_dvfs_gpu_freq_commit(g_ui32FreqIDFromPolicy, GED_DVFS_DEFAULT_COMMIT); } } } if(gpu_debug_enable) { #ifdef GED_DVFS_ENABLE GED_LOGE("%s:gpu_loading=%d %d, g_iSkipCount=%d",__func__, gpu_loading, mt_gpufreq_get_cur_freq_index(), g_iSkipCount); #endif } EXIT_ged_dvfs_run: mutex_unlock(&gsDVFSLock); }