void cmdq_core_dump_secure_metadata(cmdqSecDataStruct *pSecData) { uint32_t i = 0; cmdqSecAddrMetadataStruct *pAddr = NULL; if (NULL == pSecData) { return; } pAddr = (cmdqSecAddrMetadataStruct *)(CMDQ_U32_PTR(pSecData->addrMetadatas)); CMDQ_LOG("========= pSecData: %p dump =========\n", pSecData); CMDQ_LOG("count:%d(%d), enginesNeedDAPC:0x%llx, enginesPortSecurity:0x%llx\n", pSecData->addrMetadataCount, pSecData->addrMetadataMaxCount, pSecData->enginesNeedDAPC, pSecData->enginesNeedPortSecurity); if (NULL == pAddr) { return; } for (i = 0; i < pSecData->addrMetadataCount; i++) { CMDQ_LOG("idx:%d, type:%d, baseHandle:%x, offset:%d, size:%d, port:%d\n", i, pAddr[i].type, pAddr[i].baseHandle, pAddr[i].offset, pAddr[i].size, pAddr[i].port); } }
int32_t cmdqRecDumpCommand(cmdqRecHandle handle) { int32_t status = 0; struct TaskStruct *pTask = handle->pRunningTask; if (pTask) { /* running, so dump from core task direct */ status = cmdqCoreDebugDumpCommand(pTask); } else { /* not running, dump from rec->pBuffer */ const uint32_t *pCmd = NULL; static char textBuf[128] = { 0 }; int i = 0; CMDQ_LOG("======REC 0x%p command buffer:\n", handle->pBuffer); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 4, handle->pBuffer, handle->blockSize, false); CMDQ_LOG("======REC 0x%p command buffer END\n", handle->pBuffer); CMDQ_LOG("REC 0x%p command buffer TRANSLATED:\n", handle->pBuffer); for (i = 0, pCmd = handle->pBuffer; i < handle->blockSize; i += 8, pCmd += 2) { cmdq_core_parse_instruction(pCmd, textBuf, 128); CMDQ_LOG("%s", textBuf); } CMDQ_LOG("======REC 0x%p command END\n", handle->pBuffer); return 0; } return status; }
void cmdq_core_enable_common_clock_locked_impl(bool enable) { #ifdef CMDQ_PWR_AWARE if (enable) { CMDQ_VERBOSE("[CLOCK] Enable SMI & LARB0 Clock\n"); cmdq_dev_enable_clock_SMI_COMMON(enable); cmdq_dev_enable_clock_SMI_LARB0(enable); #if 0 /* MT_CG_DISP0_MUTEX_32K is removed in this platform */ CMDQ_LOG("[CLOCK] enable MT_CG_DISP0_MUTEX_32K\n"); enable_clock(MT_CG_DISP0_MUTEX_32K, "CMDQ_MDP"); #endif } else { CMDQ_VERBOSE("[CLOCK] Disable SMI & LARB0 Clock\n"); /* disable, reverse the sequence */ cmdq_dev_enable_clock_SMI_LARB0(enable); cmdq_dev_enable_clock_SMI_COMMON(enable); #if 0 /* MT_CG_DISP0_MUTEX_32K is removed in this platform */ CMDQ_LOG("[CLOCK] disable MT_CG_DISP0_MUTEX_32K\n"); disable_clock(MT_CG_DISP0_MUTEX_32K, "CMDQ_MDP"); #endif } #endif /* CMDQ_PWR_AWARE */ }
static void cmdq_driver_process_read_address_request(struct cmdqReadAddressStruct *req_user) { /* create kernel-space buffer for working */ uint32_t *addrs = NULL; uint32_t *values = NULL; dma_addr_t pa = 0; int i = 0; CMDQ_LOG("[READ_PA] cmdq_driver_process_read_address_request()\n"); do { if (NULL == req_user || 0 == req_user->count || NULL == CMDQ_U32_PTR(req_user->values) || NULL == CMDQ_U32_PTR(req_user->dmaAddresses)) { CMDQ_ERR("[READ_PA] invalid req_user\n"); break; } addrs = kcalloc(req_user->count, sizeof(uint32_t), GFP_KERNEL); if (NULL == addrs) { CMDQ_ERR("[READ_PA] fail to alloc addr buf\n"); break; } values = kcalloc(req_user->count, sizeof(uint32_t), GFP_KERNEL); if (NULL == values) { CMDQ_ERR("[READ_PA] fail to alloc value buf\n"); break; } /* copy from user */ if (copy_from_user (addrs, CMDQ_U32_PTR(req_user->dmaAddresses), req_user->count * sizeof(uint32_t))) { CMDQ_ERR("[READ_PA] fail to copy user dmaAddresses\n"); break; } /* actually read these PA write buffers */ for (i = 0; i < req_user->count; ++i) { pa = (0xFFFFFFFF & addrs[i]); CMDQ_LOG("[READ_PA] req read dma address 0x%pa\n", &pa); values[i] = cmdqCoreReadWriteAddress(pa); } /* copy value to user */ if (copy_to_user (CMDQ_U32_PTR(req_user->values), values, req_user->count * sizeof(uint32_t))) { CMDQ_ERR("[READ_PA] fail to copy to user value buf\n"); break; } } while (0); kfree(addrs); kfree(values); }
void cmdq_virtual_dump_gpr(void) { int i = 0; long offset = 0; uint32_t value = 0; CMDQ_LOG("========= GPR dump =========\n"); for (i = 0; i < 16; i++) { offset = CMDQ_GPR_R32(i); value = CMDQ_REG_GET32(offset); CMDQ_LOG("[GPR %2d]+0x%lx = 0x%08x\n", i, offset, value); } CMDQ_LOG("========= GPR dump =========\n"); }
int32_t cmdqRecEstimateCommandExecTime(const cmdqRecHandle handle) { int32_t time = 0; if (NULL == handle) { return -EFAULT; } CMDQ_LOG("======REC 0x%p command execution time ESTIMATE:\n", handle); time = cmdq_prof_estimate_command_exe_time(handle->pBuffer, handle->blockSize); CMDQ_LOG("======REC 0x%p END\n", handle); return time; }
static int cmdq_sec_sectrace_transact(void) { int status; CMDQ_LOG("[sectrace]-->transact\n"); status = cmdq_sec_submit_to_secure_world_async_unlocked( CMD_CMDQ_TL_SECTRACE_TRANSACT, NULL, CMDQ_INVALID_THREAD, cmdq_sec_fill_iwc_command_sectrace_unlocked, NULL); CMDQ_LOG("[sectrace]<--transact: status: %d\n", status); return status; }
static int cmdq_sec_sectrace_map(void *va, size_t size) { int status; enum mc_result mcRet; CMDQ_LOG("[sectrace]-->map: start, va:%p, size:%d\n", va, (int)size); status = 0; cmdq_sec_lock_secure_path(); do { /* HACK: submit a dummy message to ensure secure path init done */ status = cmdq_sec_submit_to_secure_world_async_unlocked( CMD_CMDQ_TL_TEST_HELLO_TL, NULL, CMDQ_INVALID_THREAD, NULL, NULL); /* map log buffer in NWd */ mcRet = mc_map(&(gCmdqSecContextHandle->sessionHandle), va, (uint32_t)size, &gCmdqSectraceMappedInfo); if (MC_DRV_OK != mcRet) { CMDQ_ERR("[sectrace]map: failed in NWd, mc_map err: 0x%x\n", mcRet); status = -EFAULT; break; } CMDQ_LOG("[sectrace]map: mc_map sectrace buffer done, gCmdqSectraceMappedInfo(va:0x%08x, size:%d)\n", gCmdqSectraceMappedInfo.secure_virt_addr, gCmdqSectraceMappedInfo.secure_virt_len); /* ask secure CMDQ to map sectrace log buffer */ status = cmdq_sec_submit_to_secure_world_async_unlocked( CMD_CMDQ_TL_SECTRACE_MAP, NULL, CMDQ_INVALID_THREAD, cmdq_sec_fill_iwc_command_sectrace_unlocked, NULL); if(0 > status) { CMDQ_ERR("[sectrace]map: failed in SWd: %d\n", status); mc_unmap(&(gCmdqSecContextHandle->sessionHandle), va, &gCmdqSectraceMappedInfo); status = -EFAULT; break; } } while(0); cmdq_sec_unlock_secure_path(); CMDQ_LOG("[sectrace]<--map: status: %d\n", status); return status; }
int32_t cmdq_sec_sectrace_init(void) { #ifdef CMDQ_SECTRACE_SUPPORT int32_t status; const uint32_t CMDQ_SECTRACE_BUFFER_SIZE_KB = 64; union callback_func sectraceCB; /* use callback_tl_function becuase CMDQ use "TCI" for inter-world communication */ sectraceCB.tl.map = cmdq_sec_sectrace_map; sectraceCB.tl.unmap = cmdq_sec_sectrace_unmap; sectraceCB.tl.transact = cmdq_sec_sectrace_transact; /* create sectrace entry in debug FS */ status = init_sectrace("CMDQ_SEC", if_tci, /* use TCI for inter world communication */ usage_tl_dr, /* print sectrace log for tl and driver */ CMDQ_SECTRACE_BUFFER_SIZE_KB, §raceCB); CMDQ_LOG("cmdq_sec_trace_init, status:%d\n", status); return 0; #else return 0; #endif }
int32_t cmdq_sec_fill_iwc_command_sectrace_unlocked(int32_t iwcCommand, void *_pTask, int32_t thread, void *_pIwc) { iwcCmdqMessage_t *pIwc; pIwc = (iwcCmdqMessage_t *)_pIwc; /* specify command id only, don't care other other */ memset(pIwc, 0x0, sizeof(iwcCmdqMessage_t)); pIwc->cmd = iwcCommand; switch (iwcCommand){ case CMD_CMDQ_TL_SECTRACE_MAP: pIwc->sectracBuffer.addr = (uint32_t)(gCmdqSectraceMappedInfo.secure_virt_addr); pIwc->sectracBuffer.size = (gCmdqSectraceMappedInfo.secure_virt_len); break; case CMD_CMDQ_TL_SECTRACE_UNMAP: case CMD_CMDQ_TL_SECTRACE_TRANSACT: default: pIwc->sectracBuffer.addr = 0; pIwc->sectracBuffer.size = 0; break; } /* medatada: debug config */ pIwc->debug.logLevel = (cmdq_core_should_print_msg()) ? (1) : (0); pIwc->debug.enableProfile = cmdq_core_profile_enabled(); CMDQ_LOG("[sectrace]SESSION_MSG: iwcCommand:%d, msg(sectraceBuffer, addr:0x%x, size:%d)\n", iwcCommand, pIwc->sectracBuffer.addr, pIwc->sectracBuffer.size); return 0; }
/******************************************************************************** * common part: for general projects *******************************************************************************/ int32_t cmdq_sec_create_shared_memory(cmdqSecSharedMemoryHandle *pHandle, const uint32_t size) { cmdqSecSharedMemoryHandle handle = NULL; void *pVA = NULL; dma_addr_t PA = 0; handle = kzalloc(sizeof(uint8_t *) * sizeof(cmdqSecSharedMemoryStruct), GFP_KERNEL); if (NULL == handle) { return -ENOMEM; } CMDQ_LOG("%s\n", __func__); /* allocate non-cachable memory */ pVA = cmdq_core_alloc_hw_buffer( cmdq_dev_get(), size, &PA, GFP_KERNEL); CMDQ_MSG("%s, MVA:%pa, pVA:%p, size:%d\n", __func__, &PA, pVA, size); if(NULL == pVA) { kfree(handle); return -ENOMEM; } /* update memory information */ handle->size = size; handle->pVABase = pVA; handle->MVABase = PA; *pHandle = handle; return 0; }
void cmdq_dev_init(struct platform_device *pDevice) { struct device_node *node = pDevice->dev.of_node; /* init cmdq device dependent data */ do { memset(&gCmdqDev, 0x0, sizeof(CmdqDeviceStruct)); gCmdqDev.pDev = &pDevice->dev; #ifdef CMDQ_OF_SUPPORT gCmdqDev.regBaseVA = (unsigned long)of_iomap(node, 0); gCmdqDev.regBasePA = (0L | 0x10212000); gCmdqDev.irqId = irq_of_parse_and_map(node, 0); gCmdqDev.irqSecId = irq_of_parse_and_map(node, 1); #else gCmdqDev.regBaseVA = (0L | GCE_BASE); gCmdqDev.regBasePA = (0L | 0x10212000); gCmdqDev.irqId = CQ_DMA_IRQ_BIT_ID; gCmdqDev.irqSecId = CQ_DMA_SEC_IRQ_BIT_ID; #endif CMDQ_LOG ("[CMDQ] platform_dev: dev: %p, PA: %lx, VA: %lx, irqId: %d, irqSecId:%d\n", gCmdqDev.pDev, gCmdqDev.regBasePA, gCmdqDev.regBaseVA, gCmdqDev.irqId, gCmdqDev.irqSecId); } while (0); /* init module VA */ cmdq_dev_init_module_base_VA(); }
const long cmdq_dev_alloc_module_base_VA_by_name(const char *name) { unsigned long VA; struct device_node *node = NULL; node = of_find_compatible_node(NULL, NULL, name); VA = (unsigned long)of_iomap(node, 0); CMDQ_LOG("DEV: VA(%s): 0x%lx\n", name, VA); return VA; }
void cmdq_dev_alloc_disp_module_PA_by_name(const char *name, int index, long *startPA, long *endPA) { struct device_node *node = NULL; struct resource res; node = of_find_compatible_node(NULL, NULL, name); of_address_to_resource(node, index, &res); *startPA = res.start; *endPA = res.end; CMDQ_LOG("DEV: PA(%s): start = 0x%lx, end = 0x%lx\n", name, *startPA, *endPA); }
int cmdq_virtual_dump_smi(const int showSmiDump) { int isSMIHang = 0; #if defined(CMDQ_CONFIG_SMI) && !defined(CONFIG_MTK_FPGA) isSMIHang = smi_debug_bus_hanging_detect_ext(SMI_DBG_DISPSYS | SMI_DBG_VDEC | SMI_DBG_IMGSYS | SMI_DBG_VENC | SMI_DBG_MJC, showSmiDump, 1); CMDQ_ERR("SMI Hang? = %d\n", isSMIHang); #else CMDQ_LOG("[WARNING]not enable SMI dump now\n"); #endif return isSMIHang; }
void cmdqSecEnableProfile(const bool enable) { #ifdef CMDQ_SECURE_PATH_SUPPORT CMDQ_LOG("[sectrace]enable profile %d\n", enable) mutex_lock(&gCmdqSecProfileLock); if (enable) { cmdq_sec_sectrace_init(); } else { cmdq_sec_sectrace_deinit(); } mutex_unlock(&gCmdqSecProfileLock); #endif }
int cmdq_core_dump_smi(const int showSmiDump) { #if 0 int isSMIHang = 0; #ifndef CONFIG_MTK_FPGA /* isSMIHang = smi_debug_bus_hanging_detect( SMI_DBG_DISPSYS | SMI_DBG_VDEC | SMI_DBG_IMGSYS | SMI_DBG_VENC | SMI_DBG_MJC, showSmiDump); */ isSMIHang = smi_debug_bus_hanging_detect_ext( SMI_DBG_DISPSYS | SMI_DBG_VDEC | SMI_DBG_IMGSYS | SMI_DBG_VENC | SMI_DBG_MJC, showSmiDump, 1); CMDQ_ERR("SMI Hang? = %d\n", isSMIHang); #endif return isSMIHang; #else CMDQ_LOG("[WARNING]not enable SMI dump now\n"); return 0; #endif }
int32_t cmdq_sec_fill_iwc_cancel_msg_unlocked(int32_t iwcCommand, void *_pTask, int32_t thread, void *_pIwc) { const TaskStruct *pTask = (TaskStruct *)_pTask; iwcCmdqMessage_t *pIwc; pIwc = (iwcCmdqMessage_t *)_pIwc; memset(pIwc, 0x0, sizeof(iwcCmdqMessage_t)); pIwc->cmd = iwcCommand; pIwc->cancelTask.waitCookie = pTask->secData.waitCookie; pIwc->cancelTask.thread = thread; /* medatada: debug config */ pIwc->debug.logLevel = (cmdq_core_should_print_msg()) ? (1) : (0); pIwc->debug.enableProfile = cmdq_core_profile_enabled(); CMDQ_LOG("FILL:CANCEL_TASK: task: %p, thread:%d, cookie:%d\n", pTask, thread, pTask->secData.waitCookie); return 0; }
static int cmdq_sec_sectrace_unmap(void *va, size_t size) { int status; enum mc_result mcRet; status = 0; cmdq_sec_lock_secure_path(); do { if(NULL == gCmdqSecContextHandle) { status = -EFAULT; break; } /* ask secure CMDQ to unmap sectrace log buffer */ status = cmdq_sec_submit_to_secure_world_async_unlocked( CMD_CMDQ_TL_SECTRACE_UNMAP, NULL, CMDQ_INVALID_THREAD, cmdq_sec_fill_iwc_command_sectrace_unlocked, NULL); if(0 > status) { CMDQ_ERR("[sectrace]unmap: failed in SWd: %d\n", status); mc_unmap(&(gCmdqSecContextHandle->sessionHandle), va, &gCmdqSectraceMappedInfo); status = -EFAULT; break; } mcRet = mc_unmap(&(gCmdqSecContextHandle->sessionHandle), va, &gCmdqSectraceMappedInfo); } while(0); cmdq_sec_unlock_secure_path(); CMDQ_LOG("[sectrace]unmap: status: %d\n", status); return status; }
static long cmdq_ioctl(struct file *pFile, unsigned int code, unsigned long param) { struct cmdqCommandStruct command; struct cmdqJobStruct job; int count[CMDQ_MAX_ENGINE_COUNT]; struct TaskStruct *pTask; int32_t status; struct cmdqJobResultStruct jobResult; uint32_t *userRegValue = NULL; uint32_t userRegCount = 0; /* backup value after task release */ uint32_t regCount = 0, regCountUserSpace = 0, regUserToken = 0; switch (code) { case CMDQ_IOCTL_EXEC_COMMAND: if (copy_from_user(&command, (void *)param, sizeof(cmdqCommandStruct))) return -EFAULT; /* insert private_data for resource reclaim */ command.privateData = (cmdqU32Ptr_t) (unsigned long)(pFile->private_data); if (cmdq_driver_process_command_request(&command)) return -EFAULT; break; case CMDQ_IOCTL_QUERY_USAGE: if (cmdqCoreQueryUsage(count)) return -EFAULT; if (copy_to_user((void *)param, count, sizeof(int32_t) * CMDQ_MAX_ENGINE_COUNT)) { CMDQ_ERR("CMDQ_IOCTL_QUERY_USAGE copy_to_user failed\n"); return -EFAULT; } break; case CMDQ_IOCTL_ASYNC_JOB_EXEC: if (copy_from_user(&job, (void *)param, sizeof(cmdqJobStruct))) return -EFAULT; /* not support secure path for async ioctl yet */ if (true == job.command.secData.isSecure) { CMDQ_ERR("not support secure path for CMDQ_IOCTL_ASYNC_JOB_EXEC\n"); return -EFAULT; } /* backup */ userRegCount = job.command.regRequest.count; /* insert private_data for resource reclaim */ job.command.privateData = (cmdqU32Ptr_t) (unsigned long)(pFile->private_data); /* create kernel-space address buffer */ status = cmdq_driver_create_reg_address_buffer(&job.command); if (0 != status) return status; /* scenario id fixup */ cmdq_core_fix_command_scenario_for_user_space(&job.command); status = cmdqCoreSubmitTaskAsync(&job.command, NULL, 0, &pTask); /* store user space request count in TaskStruct */ /* for later retrieval */ if (pTask) { pTask->regCountUserSpace = userRegCount; pTask->regUserToken = job.command.debugRegDump; } /* we don't need regAddress anymore, free it now */ kfree(CMDQ_U32_PTR(job.command.regRequest.regAddresses)); job.command.regRequest.regAddresses = (cmdqU32Ptr_t) (unsigned long)(NULL); if (status >= 0) { job.hJob = (unsigned long)pTask; if (copy_to_user((void *)param, (void *)&job, sizeof(cmdqJobStruct))) { CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC copy_to_user failed\n"); return -EFAULT; } } else { job.hJob = (unsigned long)NULL; return -EFAULT; } break; case CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE: if (copy_from_user(&jobResult, (void *)param, sizeof(jobResult))) { CMDQ_ERR("copy_from_user jobResult fail\n"); return -EFAULT; } /* verify job handle */ if (!cmdqIsValidTaskPtr((TaskStruct *) (unsigned long)jobResult.hJob)) { CMDQ_ERR("invalid task ptr = 0x%llx\n", jobResult.hJob); return -EFAULT; } pTask = (TaskStruct *) (unsigned long)jobResult.hJob; /* utility service, fill the engine flag. */ /* this is required by MDP. */ jobResult.engineFlag = pTask->engineFlag; /* check if reg buffer suffices */ if (jobResult.regValue.count < pTask->regCountUserSpace) { jobResult.regValue.count = pTask->regCountUserSpace; if (copy_to_user((void *)param, (void *)&jobResult, sizeof(jobResult))) { CMDQ_ERR("copy_to_user fail, line=%d\n", __LINE__); return -EINVAL; } CMDQ_ERR("insufficient register buffer\n"); return -ENOMEM; } /* inform client the actual read register count */ jobResult.regValue.count = pTask->regCountUserSpace; /* update user space before we replace the regValues pointer. */ if (copy_to_user((void *)param, (void *)&jobResult, sizeof(jobResult))) { CMDQ_ERR("copy_to_user fail line=%d\n", __LINE__); return -EINVAL; } /* allocate kernel space result buffer */ /* which contains kernel + user space requests */ userRegValue = CMDQ_U32_PTR(jobResult.regValue.regValues); jobResult.regValue.regValues = (cmdqU32Ptr_t) (unsigned long) (kzalloc(pTask->regCount * sizeof(uint32_t), GFP_KERNEL)); jobResult.regValue.count = pTask->regCount; if (NULL == CMDQ_U32_PTR(jobResult.regValue.regValues)) { CMDQ_ERR("no reg value buffer\n"); return -ENOMEM; } /* backup value after task release */ regCount = pTask->regCount; regCountUserSpace = pTask->regCountUserSpace; regUserToken = pTask->regUserToken; /* make sure the task is running and wait for it */ status = cmdqCoreWaitResultAndReleaseTask(pTask, &jobResult.regValue, msecs_to_jiffies (CMDQ_DEFAULT_TIMEOUT_MS)); if (status < 0) { CMDQ_ERR("waitResultAndReleaseTask fail=%d\n", status); /* free kernel space result buffer */ kfree(CMDQ_U32_PTR(jobResult.regValue.regValues)); return status; } /* pTask is released, do not access it any more */ pTask = NULL; /* notify kernel space dump callback */ if (regCount > regCountUserSpace) { CMDQ_VERBOSE("kernel space reg dump = %d, %d, %d\n", regCount, regCountUserSpace, regUserToken); status = cmdqCoreDebugRegDumpEnd(regUserToken, regCount - regCountUserSpace, CMDQ_U32_PTR(jobResult.regValue.regValues + regCountUserSpace)); if (0 != status) { /* Error status print */ CMDQ_ERR("cmdqCoreDebugRegDumpEnd returns %d\n", status); } } /* copy result to user space */ if (copy_to_user ((void *)userRegValue, (void *)(unsigned long)jobResult.regValue.regValues, regCountUserSpace * sizeof(uint32_t))) { CMDQ_ERR("Copy REGVALUE to user space failed\n"); return -EFAULT; } if (jobResult.readAddress.count > 0) cmdq_driver_process_read_address_request(&jobResult.readAddress); /* free kernel space result buffer */ kfree(CMDQ_U32_PTR(jobResult.regValue.regValues)); break; case CMDQ_IOCTL_ALLOC_WRITE_ADDRESS: do { cmdqWriteAddressStruct addrReq; dma_addr_t paStart = 0; CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS\n"); if (copy_from_user(&addrReq, (void *)param, sizeof(addrReq))) { CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_from_user failed\n"); return -EFAULT; } status = cmdqCoreAllocWriteAddress(addrReq.count, &paStart); if (0 != status) { CMDQ_ERR ("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS cmdqCoreAllocWriteAddress() failed\n"); return status; } addrReq.startPA = (uint32_t) paStart; CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS get 0x%08x\n", addrReq.startPA); if (copy_to_user((void *)param, &addrReq, sizeof(addrReq))) { CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_to_user failed\n"); return -EFAULT; } status = 0; } while (0); break; case CMDQ_IOCTL_FREE_WRITE_ADDRESS: do { cmdqWriteAddressStruct freeReq; CMDQ_LOG("CMDQ_IOCTL_FREE_WRITE_ADDRESS\n"); if (copy_from_user(&freeReq, (void *)param, sizeof(freeReq))) { CMDQ_ERR("CMDQ_IOCTL_FREE_WRITE_ADDRESS copy_from_user failed\n"); return -EFAULT; } status = cmdqCoreFreeWriteAddress(freeReq.startPA); if (0 != status) return status; status = 0; } while (0); break; case CMDQ_IOCTL_READ_ADDRESS_VALUE: do { cmdqReadAddressStruct readReq; CMDQ_LOG("CMDQ_IOCTL_READ_ADDRESS_VALUE\n"); if (copy_from_user(&readReq, (void *)param, sizeof(readReq))) { CMDQ_ERR("CMDQ_IOCTL_READ_ADDRESS_VALUE copy_from_user failed\n"); return -EFAULT; } /* this will copy result to readReq->values buffer */ cmdq_driver_process_read_address_request(&readReq); status = 0; } while (0); break; case CMDQ_IOCTL_QUERY_CAP_BITS: do { int capBits = 0; if (cmdq_driver_support_wait_and_receive_event_in_same_tick()) capBits |= (1L << CMDQ_CAP_WFE); else capBits &= ~(1L << CMDQ_CAP_WFE); if (copy_to_user((void *)param, &capBits, sizeof(int))) { CMDQ_ERR("Copy capacity bits to user space failed\n"); return -EFAULT; } } while (0); break; case CMDQ_IOCTL_QUERY_DTS: do { cmdqDTSDataStruct *pDtsData; pDtsData = cmdq_core_get_whole_DTS_Data(); if (copy_to_user((void *)param, pDtsData, sizeof(cmdqDTSDataStruct))) { CMDQ_ERR("Copy device tree information to user space failed\n"); return -EFAULT; } } while (0); break; case CMDQ_IOCTL_NOTIFY_ENGINE: do { uint64_t engineFlag; if (copy_from_user(&engineFlag, (void *)param, sizeof(uint64_t))) { CMDQ_ERR("CMDQ_IOCTL_NOTIFY_ENGINE copy_from_user failed\n"); return -EFAULT; } cmdqCoreLockResource(engineFlag, true); } while (0); break; default: CMDQ_ERR("unrecognized ioctl 0x%08x\n", code); return -ENOIOCTLCMD; } return 0; }
static long cmdq_ioctl(struct file *pFile, unsigned int code, unsigned long param) { int mutex; struct cmdqCommandStruct command; struct cmdqJobStruct job; struct cmdqFileNodeStruct *pNode; unsigned long flags; int count[CMDQ_MAX_ENGINE_COUNT]; struct TaskStruct *pTask; int32_t status; struct cmdqJobResultStruct jobResult; uint32_t *userRegValue = NULL; uint32_t userRegCount = 0; /* backup value after task release */ uint32_t regCount = 0, regCountUserSpace = 0, regUserToken = 0; switch (code) { case CMDQ_IOCTL_LOCK_MUTEX: mutex = cmdqMutexAcquire(); if (-1 == mutex) return -IOCTL_RET_LOCK_MUTEX_FAIL; if (copy_to_user((void *)param, &mutex, sizeof(int))) { CMDQ_ERR("Copy mutex number to user failed\n"); cmdqMutexRelease(mutex); return -IOCTL_RET_COPY_MUTEX_NUM_TO_USER_FAIL; } /* register mutex into file node data */ pNode = (struct cmdqFileNodeStruct *)pFile->private_data; if (pNode) { spin_lock_irqsave(&pNode->nodeLock, flags); pNode->mutexFlag |= (1 << mutex); spin_unlock_irqrestore(&pNode->nodeLock, flags); } break; case CMDQ_IOCTL_UNLOCK_MUTEX: if (copy_from_user(&mutex, (void *)param, sizeof(int))) { CMDQ_ERR("Copy mutex number from user failed\n"); return -IOCLT_RET_COPY_MUTEX_NUM_FROM_USER_FAIL; } status = cmdqMutexRelease(mutex); if (status < 0) return -IOCTL_RET_RELEASE_MUTEX_FAIL; if (-1 != mutex) { pNode = (struct cmdqFileNodeStruct *)pFile->private_data; spin_lock_irqsave(&pNode->nodeLock, flags); pNode->mutexFlag &= ~(1 << mutex); spin_unlock_irqrestore(&pNode->nodeLock, flags); } break; case CMDQ_IOCTL_EXEC_COMMAND: if (copy_from_user(&command, (void *)param, sizeof(struct cmdqCommandStruct))) return -IOCTL_RET_COPY_EXEC_CMD_FROM_USER_FAIL; if (cmdqCoreIsEarlySuspended() && (CMDQ_SCENARIO_USER_MDP == command.scenario)) return -IOCTL_RET_IS_SUSPEND_WHEN_EXEC_CMD; /* insert private_data for resource reclaim */ command.privateData = (cmdqU32Ptr_t) pFile->private_data; if (cmdq_driver_process_command_request(&command)) return -IOCTL_RET_PROCESS_CMD_REQUEST_FAIL; break; case CMDQ_IOCTL_QUERY_USAGE: if (cmdqCoreQueryUsage(count)) return -IOCLT_RET_QUERY_USAGE_FAIL; if (copy_to_user((void *)param, count, sizeof(int32_t) * CMDQ_MAX_ENGINE_COUNT)) { CMDQ_ERR("CMDQ_IOCTL_QUERY_USAGE copy_to_user failed\n"); return -IOCTL_RET_COPY_USAGE_TO_USER_FAIL; } break; case CMDQ_IOCTL_ASYNC_JOB_EXEC: if (copy_from_user(&job, (void *)param, sizeof(struct cmdqJobStruct))) return -IOCTL_RET_COPY_ASYNC_JOB_EXEC_FROM_USER_FAIL; if (cmdqCoreIsEarlySuspended() && (CMDQ_SCENARIO_USER_MDP == job.command.scenario)) { CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC suspended, return\n"); return -IOCTL_RET_IS_SUSPEND_WHEN_ASYNC_JOB_EXEC; } /* not support secure path for async ioctl yet */ if (true == job.command.secData.isSecure) { CMDQ_ERR("not support secure path for CMDQ_IOCTL_ASYNC_JOB_EXEC\n"); return -IOCTL_RET_NOT_SUPPORT_SEC_PATH_FOR_ASYNC_JOB_EXEC; } /* backup */ userRegCount = job.command.regRequest.count; /* insert private_data for resource reclaim */ job.command.privateData = (cmdqU32Ptr_t) (unsigned long)(pFile->private_data); /* create kernel-space address buffer */ status = cmdq_driver_create_reg_address_buffer(&job.command); if (0 != status) return -IOCTL_RET_CREATE_REG_ADDR_BUF_FAIL; /* scenario id fixup */ if ((CMDQ_SCENARIO_USER_DISP_COLOR == job.command.scenario) || (CMDQ_SCENARIO_USER_MDP == job.command.scenario)) { CMDQ_VERBOSE("user space request, scenario:%d\n", job.command.scenario); } else { CMDQ_LOG("[WARNING]fix user space request to CMDQ_SCENARIO_USER_SPACE\n"); job.command.scenario = CMDQ_SCENARIO_USER_SPACE; } status = cmdqCoreSubmitTaskAsync(&job.command, NULL, 0, &pTask); /* store user space request count in struct TaskStruct */ /* for later retrieval */ if (pTask) { pTask->regCountUserSpace = userRegCount; pTask->regUserToken = job.command.debugRegDump; } /* we don't need regAddress anymore, free it now */ kfree(CMDQ_U32_PTR(job.command.regRequest.regAddresses)); job.command.regRequest.regAddresses = (cmdqU32Ptr_t) (unsigned long)(NULL); if (status >= 0) { job.hJob = (unsigned long)pTask; if (copy_to_user((void *)param, (void *)&job, sizeof(struct cmdqJobStruct))) { CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC copy_to_user failed\n"); return -IOCLT_RET_COPY_ASYNC_JOB_EXEC_TO_USER_FAIL; } } else { job.hJob = (unsigned long)NULL; return -IOCTL_RET_SUBMIT_TASK_ASYNC_FAILED; } break; case CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE: if (copy_from_user(&jobResult, (void *)param, sizeof(jobResult))) { CMDQ_ERR("copy_from_user jobResult fail\n"); return -IOCTL_RET_COPY_ASYNC_JOB_WAIT_AND_CLOSE_FROM_USER_FAIL; } if (cmdqCoreIsEarlySuspended() && (CMDQ_SCENARIO_USER_MDP == job.command.scenario)) { CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE suspended, return\n"); return -IOCTL_RET_IS_SUSPEND_WHEN_ASYNC_JOB_WAIT_AND_CLOSE; } /* verify job handle */ if (!cmdqIsValidTaskPtr((struct TaskStruct *)(unsigned long)jobResult.hJob)) { CMDQ_ERR("invalid task ptr = 0x%llx\n", jobResult.hJob); return -IOCTL_RET_INVALID_TASK_PTR; } pTask = (struct TaskStruct *)(unsigned long)jobResult.hJob; /* utility service, fill the engine flag. */ /* this is required by MDP. */ jobResult.engineFlag = pTask->engineFlag; /* check if reg buffer suffices */ if (jobResult.regValue.count < pTask->regCountUserSpace) { jobResult.regValue.count = pTask->regCountUserSpace; if (copy_to_user((void *)param, (void *)&jobResult, sizeof(jobResult))) { CMDQ_ERR("copy_to_user fail, line=%d\n", __LINE__); return -IOCTL_RET_COPY_JOB_RESULT_TO_USER1_FAIL; } CMDQ_ERR("insufficient register buffer\n"); return -IOCTL_RET_NOT_ENOUGH_REGISTER_BUFFER; } /* inform client the actual read register count */ jobResult.regValue.count = pTask->regCountUserSpace; /* update user space before we replace the regValues pointer. */ if (copy_to_user((void *)param, (void *)&jobResult, sizeof(jobResult))) { CMDQ_ERR("copy_to_user fail line=%d\n", __LINE__); return -IOCTL_RET_COPY_JOB_RESULT_TO_USER2_FAIL; } /* allocate kernel space result buffer */ /* which contains kernel + user space requests */ userRegValue = CMDQ_U32_PTR(jobResult.regValue.regValues); jobResult.regValue.regValues = (cmdqU32Ptr_t) (unsigned long)(kzalloc(pTask->regCount * sizeof(uint32_t), GFP_KERNEL)); jobResult.regValue.count = pTask->regCount; if (NULL == CMDQ_U32_PTR(jobResult.regValue.regValues)) { CMDQ_ERR("no reg value buffer\n"); return -IOCTL_RET_NO_REG_VAL_BUFFER; } /* backup value after task release */ regCount = pTask->regCount; regCountUserSpace = pTask->regCountUserSpace; regUserToken = pTask->regUserToken; /* make sure the task is running and wait for it */ status = cmdqCoreWaitResultAndReleaseTask(pTask, &jobResult.regValue, msecs_to_jiffies (CMDQ_DEFAULT_TIMEOUT_MS)); if (status < 0) { CMDQ_ERR("waitResultAndReleaseTask fail=%d\n", status); /* free kernel space result buffer */ kfree(CMDQ_U32_PTR(jobResult.regValue.regValues)); return -IOCTL_RET_WAIT_RESULT_AND_RELEASE_TASK_FAIL; } /* pTask is released, do not access it any more */ pTask = NULL; /* notify kernel space dump callback */ if (regCount > regCountUserSpace) { CMDQ_VERBOSE("kernel space reg dump = %d, %d, %d\n", regCount, regCountUserSpace, regUserToken); status = cmdqCoreDebugRegDumpEnd(regUserToken, regCount - regCountUserSpace, CMDQ_U32_PTR(jobResult.regValue.regValues + regCountUserSpace)); if (0 != status) CMDQ_ERR("cmdqCoreDebugRegDumpEnd returns %d\n", status); } /* copy result to user space */ if (copy_to_user ((void *)userRegValue, (void *)(unsigned long)jobResult.regValue.regValues, regCountUserSpace * sizeof(uint32_t))) { CMDQ_ERR("Copy REGVALUE to user space failed\n"); return -IOCLT_RET_COPY_REG_VALUE_TO_USER_FAIL; } if (jobResult.readAddress.count > 0) cmdq_driver_process_read_address_request(&jobResult.readAddress); /* free kernel space result buffer */ kfree(CMDQ_U32_PTR(jobResult.regValue.regValues)); break; case CMDQ_IOCTL_ALLOC_WRITE_ADDRESS: do { struct cmdqWriteAddressStruct addrReq; dma_addr_t paStart = 0; CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS\n"); if (copy_from_user(&addrReq, (void *)param, sizeof(addrReq))) { CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_from_user failed\n"); return -IOCTL_RET_COPY_ALLOC_WRITE_ADDR_FROM_USER_FAIL; } status = cmdqCoreAllocWriteAddress(addrReq.count, &paStart); if (0 != status) { CMDQ_ERR ("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS cmdqCoreAllocWriteAddress() failed\n"); return -IOCTL_RET_ALLOC_WRITE_ADDR_FAIL; } addrReq.startPA = (uint32_t) paStart; CMDQ_LOG("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS get 0x%08x\n", addrReq.startPA); if (copy_to_user((void *)param, &addrReq, sizeof(addrReq))) { CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS copy_to_user failed\n"); return -IOCTL_RET_COPY_ALLOC_WRITE_ADDR_TO_USER_FAIL; } status = 0; } while (0); break; case CMDQ_IOCTL_FREE_WRITE_ADDRESS: do { struct cmdqWriteAddressStruct freeReq; CMDQ_LOG("CMDQ_IOCTL_FREE_WRITE_ADDRESS\n"); if (copy_from_user(&freeReq, (void *)param, sizeof(freeReq))) { CMDQ_ERR("CMDQ_IOCTL_FREE_WRITE_ADDRESS copy_from_user failed\n"); return -IOCTL_RET_COPY_FREE_WRITE_ADDR_FROM_USER_FAIL; } status = cmdqCoreFreeWriteAddress(freeReq.startPA); if (0 != status) return -IOCTL_RET_FREE_WRITE_ADDR_FAIL; status = 0; } while (0); break; case CMDQ_IOCTL_READ_ADDRESS_VALUE: do { struct cmdqReadAddressStruct readReq; CMDQ_LOG("CMDQ_IOCTL_READ_ADDRESS_VALUE\n"); if (copy_from_user(&readReq, (void *)param, sizeof(readReq))) { CMDQ_ERR("CMDQ_IOCTL_READ_ADDRESS_VALUE copy_from_user failed\n"); return -IOCTL_RET_COPY_READ_ADDR_VAL_FROM_USER_FAIL; } /* this will copy result to readReq->values buffer */ cmdq_driver_process_read_address_request(&readReq); status = 0; } while (0); break; case CMDQ_IOCTL_QUERY_CAP_BITS: do { int capBits = 0; if (cmdq_core_support_wait_and_receive_event_in_same_tick()) capBits |= (1L << CMDQ_CAP_WFE); else capBits &= ~(1L << CMDQ_CAP_WFE); if (copy_to_user((void *)param, &capBits, sizeof(int))) { CMDQ_ERR("Copy capacity bits to user space failed\n"); return -IOCTL_RET_COPY_CAP_BITS_TO_USER_FAIL; } } while (0); break; case CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION: #ifdef CMDQ_SECURE_PATH_SUPPORT do { struct cmdqSyncHandleHdcpStruct syncHandle; if (copy_from_user(&syncHandle, (void *)param, sizeof(syncHandle))) { CMDQ_ERR ("CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION copy_from_user failed\n"); return -IOCTL_RET_COPY_HDCP_VERSION_FROM_USER_FAIL; } status = cmdq_sec_sync_handle_hdcp_unlock(syncHandle); if (0 != status) CMDQ_ERR("cmdq_sec_sync_handle_hdcp_unlock returns %d\n", status); } while (0); #else CMDQ_ERR("SVP not supported\n"); return -IOCTL_RET_SVP_NOT_SUPPORT; #endif break; default: CMDQ_ERR("unrecognized ioctl 0x%08x\n", code); CMDQ_ERR("CMDQ_IOCTL_LOCK_MUTEX:0x%08lx sizeof(int) = %ld\n", CMDQ_IOCTL_LOCK_MUTEX, sizeof(int)); CMDQ_ERR("CMDQ_IOCTL_UNLOCK_MUTEX:0x%08lx sizeof(int) = %ld\n", CMDQ_IOCTL_UNLOCK_MUTEX, sizeof(int)); CMDQ_ERR("CMDQ_IOCTL_EXEC_COMMAND:0x%08lx sizeof(struct cmdqCommandStruct) = %ld\n", CMDQ_IOCTL_EXEC_COMMAND, sizeof(struct cmdqCommandStruct)); CMDQ_ERR("CMDQ_IOCTL_QUERY_USAGE:0x%08lx sizeof(struct cmdqUsageInfoStruct) = %ld\n", CMDQ_IOCTL_QUERY_USAGE, sizeof(struct cmdqUsageInfoStruct)); CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_EXEC:0x%08lx sizeof(struct cmdqJobStruct) = %ld\n", CMDQ_IOCTL_ASYNC_JOB_EXEC, sizeof(struct cmdqJobStruct)); CMDQ_ERR("CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE:0x%08lx sizeof(struct cmdqJobResultStruct) = %ld\n", CMDQ_IOCTL_ASYNC_JOB_WAIT_AND_CLOSE, sizeof(struct cmdqJobResultStruct)); CMDQ_ERR("CMDQ_IOCTL_ALLOC_WRITE_ADDRESS:0x%08lx sizeof(struct cmdqWriteAddressStruct) = %ld\n", CMDQ_IOCTL_ALLOC_WRITE_ADDRESS, sizeof(struct cmdqWriteAddressStruct)); CMDQ_ERR("CMDQ_IOCTL_FREE_WRITE_ADDRESS:0x%08lx sizeof(struct cmdqWriteAddressStruct) = %ld\n", CMDQ_IOCTL_FREE_WRITE_ADDRESS, sizeof(struct cmdqWriteAddressStruct)); CMDQ_ERR("CMDQ_IOCTL_READ_ADDRESS_VALUE:0x%08lx sizeof(struct cmdqReadAddressStruct) = %ld\n", CMDQ_IOCTL_READ_ADDRESS_VALUE, sizeof(struct cmdqReadAddressStruct)); CMDQ_ERR("CMDQ_IOCTL_QUERY_CAP_BITS:0x%08lx sizeof(int) = %ld\n", CMDQ_IOCTL_QUERY_CAP_BITS, sizeof(int)); CMDQ_ERR("CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION:0x%08lx sizeof(struct cmdqSyncHandleHdcpStruct) = %ld\n", CMDQ_IOCTL_SYNC_BUF_HDCP_VERSION, sizeof(struct cmdqSyncHandleHdcpStruct)); return -IOCTL_RET_UNRECOGNIZED_IOCTL; } return IOCTL_RET_SUCCESS; }
static long cmdq_driver_process_command_request(struct cmdqCommandStruct *pCommand) { int32_t status = 0; uint32_t *userRegValue = NULL; uint32_t userRegCount = 0; if (pCommand->regRequest.count != pCommand->regValue.count) { CMDQ_ERR("mismatch regRequest and regValue\n"); return -EFAULT; } /* allocate secure medatata */ status = cmdq_driver_create_secure_medadata(pCommand); if (0 != status) return status; /* backup since we are going to replace these */ userRegValue = CMDQ_U32_PTR(pCommand->regValue.regValues); userRegCount = pCommand->regValue.count; /* create kernel-space address buffer */ status = cmdq_driver_create_reg_address_buffer(pCommand); if (0 != status) { /* free secure path metadata */ cmdq_driver_destroy_secure_medadata(pCommand); return status; } /* create kernel-space value buffer */ pCommand->regValue.regValues = (cmdqU32Ptr_t) (unsigned long) kzalloc(pCommand->regRequest.count * sizeof(uint32_t), GFP_KERNEL); pCommand->regValue.count = pCommand->regRequest.count; if (NULL == CMDQ_U32_PTR(pCommand->regValue.regValues)) { kfree(CMDQ_U32_PTR(pCommand->regRequest.regAddresses)); return -ENOMEM; } /* scenario id fixup */ if ((CMDQ_SCENARIO_USER_DISP_COLOR == pCommand->scenario) || (CMDQ_SCENARIO_USER_MDP == pCommand->scenario)) { CMDQ_VERBOSE("user space request, scenario:%d\n", pCommand->scenario); } else { CMDQ_LOG("[WARNING]fix user space request to CMDQ_SCENARIO_USER_SPACE\n"); pCommand->scenario = CMDQ_SCENARIO_USER_SPACE; } if (CMDQ_SCENARIO_USER_MDP == pCommand->scenario) CMDQ_MSG("srcHandle=0x%08x, dstHandle=0x%08x\n", pCommand->secData.srcHandle, pCommand->secData.dstHandle); status = cmdqCoreSubmitTask(pCommand); if (0 > status) { CMDQ_ERR("Submit user commands for execution failed = %d\n", status); cmdq_driver_destroy_secure_medadata(pCommand); kfree(CMDQ_U32_PTR(pCommand->regRequest.regAddresses)); kfree(CMDQ_U32_PTR(pCommand->regValue.regValues)); return -EFAULT; } /* notify kernel space dump callback */ if (0 != pCommand->debugRegDump) { status = cmdqCoreDebugRegDumpEnd(pCommand->debugRegDump, pCommand->regRequest.count - userRegCount, CMDQ_U32_PTR(pCommand->regValue.regValues) + userRegCount); if (0 != status) CMDQ_ERR("cmdqCoreDebugRegDumpEnd returns %d\n", status); } /* copy back to user space buffer */ if (userRegValue && userRegCount) { /* copy results back to user space */ CMDQ_VERBOSE("regValue[0] is %d\n", CMDQ_U32_PTR(pCommand->regValue.regValues)[0]); if (copy_to_user (userRegValue, CMDQ_U32_PTR(pCommand->regValue.regValues), userRegCount * sizeof(uint32_t))) { CMDQ_ERR("Copy REGVALUE to user space failed\n"); } } /* free allocated kernel buffers */ kfree(CMDQ_U32_PTR(pCommand->regRequest.regAddresses)); kfree(CMDQ_U32_PTR(pCommand->regValue.regValues)); if (pCommand->readAddress.count > 0) cmdq_driver_process_read_address_request(&pCommand->readAddress); /* free allocated secure metadata */ cmdq_driver_destroy_secure_medadata(pCommand); return 0; }
static int cmdq_probe(struct platform_device *pDevice) { int status; struct device *object; CMDQ_MSG("CMDQ driver probe begin\n"); /* init cmdq device related data */ cmdq_dev_init(pDevice); /* init cmdq context */ cmdqCoreInitialize(); status = alloc_chrdev_region(&gCmdqDevNo, 0, 1, CMDQ_DRIVER_DEVICE_NAME); if (status != 0) CMDQ_ERR("Get CMDQ device major number(%d) failed(%d)\n", gCmdqDevNo, status); else CMDQ_MSG("Get CMDQ device major number(%d) success(%d)\n", gCmdqDevNo, status); /* ioctl access point (/dev/mtk_cmdq) */ gCmdqCDev = cdev_alloc(); gCmdqCDev->owner = THIS_MODULE; gCmdqCDev->ops = &cmdqOP; status = cdev_add(gCmdqCDev, gCmdqDevNo, 1); gCMDQClass = class_create(THIS_MODULE, CMDQ_DRIVER_DEVICE_NAME); object = device_create(gCMDQClass, NULL, gCmdqDevNo, NULL, CMDQ_DRIVER_DEVICE_NAME); CMDQ_LOG("register IRQ:%d\n", cmdq_dev_get_irq_id()); status = request_irq(cmdq_dev_get_irq_id(), cmdq_irq_handler, IRQF_TRIGGER_LOW, CMDQ_DRIVER_DEVICE_NAME, gCmdqCDev); if (status != 0) { CMDQ_ERR("Register cmdq driver irq handler(%d) failed(%d)\n", gCmdqDevNo, status); return -EFAULT; } #if 0 /* remove register secure IRQ in Normal world . TZ register instead */ /* although secusre CMDQ driver is responsible for handle secure IRQ, */ /* MUST registet secure IRQ to GIC in normal world to ensure it will be initialize correctly */ /* (that's because t-base does not support GIC init IRQ in secure world...) */ CMDQ_LOG("register sec IRQ:%d\n", cmdq_dev_get_irq_secure_id()); status = request_irq(cmdq_dev_get_irq_secure_id(), cmdq_sec_irq_handler, IRQF_TRIGGER_LOW, "TEE IRQ", gCmdqCDev); if (status != 0) { CMDQ_ERR("Register cmdq driver secure irq handler(%d) failed(%d)\n", gCmdqDevNo, status); return -EFAULT; } #endif /* CMDQ_ERR("prepare to create device mtk_cmdq\n"); */ /* global ioctl access point (/proc/mtk_cmdq) */ if (NULL == proc_create(CMDQ_DRIVER_DEVICE_NAME, 0644, NULL, &cmdqOP)) { CMDQ_ERR("CMDQ procfs node create failed\n"); return -EFAULT; } #ifdef CMDQ_OF_SUPPORT /* CCF - Common Clock Framework */ cmdq_core_get_clk_map(pDevice); #endif /* proc debug access point */ cmdq_create_debug_entries(); /* device attributes for debugging */ device_create_file(&pDevice->dev, &dev_attr_status); device_create_file(&pDevice->dev, &dev_attr_error); device_create_file(&pDevice->dev, &dev_attr_record); device_create_file(&pDevice->dev, &dev_attr_log_level); device_create_file(&pDevice->dev, &dev_attr_profile_enable); CMDQ_MSG("CMDQ driver probe end\n"); return 0; }
int32_t cmdq_sec_submit_to_secure_world_async_unlocked(uint32_t iwcCommand, TaskStruct *pTask, int32_t thread, CmdqSecFillIwcCB iwcFillCB, void *data) { const int32_t tgid = current->tgid; const int32_t pid = current->pid; cmdqSecContextHandle handle = NULL; int32_t status = 0; int32_t duration = 0; CMDQ_TIME tEntrySec; CMDQ_TIME tExitSec; CMDQ_MSG("[SEC]-->SEC_SUBMIT: tgid[%d:%d]\n", tgid, pid); do { /* find handle first */ /* Unlike tBase user space API, * tBase kernel API maintains a GLOBAL table to control mobicore device reference count. * For kernel spece user, mc_open_device and session_handle don't depend on the process context. * Therefore we use global secssion handle to inter-world commumication. */ if(NULL == gCmdqSecContextHandle) { gCmdqSecContextHandle = cmdq_sec_context_handle_create(current->tgid); } handle = gCmdqSecContextHandle; if (NULL == handle) { CMDQ_ERR("SEC_SUBMIT: tgid %d err[NULL secCtxHandle]\n", tgid); status = -(CMDQ_ERR_NULL_SEC_CTX_HANDLE); break; } if (0 > cmdq_sec_setup_context_session(handle)) { status = -(CMDQ_ERR_SEC_CTX_SETUP); break; } tEntrySec = sched_clock(); status = cmdq_sec_send_context_session_message( handle, iwcCommand, pTask, thread, iwcFillCB, data); tExitSec = sched_clock(); CMDQ_GET_TIME_IN_US_PART(tEntrySec, tExitSec, duration); cmdq_sec_track_task_record(iwcCommand, pTask, &tEntrySec, &tExitSec); /* release resource */ #if !(CMDQ_OPEN_SESSION_ONCE) cmdq_sec_teardown_context_session(handle) #endif /* Note we entry secure for config only and wait result in normal world. */ /* No need reset module HW for config failed case*/ } while (0); if (-ETIMEDOUT == status) { /* t-base strange issue, mc_wait_notification false timeout when secure world has done */ /* becuase retry may failed, give up retry method */ CMDQ_AEE("CMDQ", "[SEC]<--SEC_SUBMIT: err[%d][mc_wait_notification timeout], pTask[0x%p], THR[%d], tgid[%d:%d], config_duration_ms[%d], cmdId[%d]\n", status, pTask, thread, tgid, pid, duration, iwcCommand); } else if (0 > status) { /* dump metadata first */ if (pTask) { cmdq_core_dump_secure_metadata(&(pTask->secData)); } /* throw AEE */ CMDQ_AEE("CMDQ", "[SEC]<--SEC_SUBMIT: err[%d], pTask[0x%p], THR[%d], tgid[%d:%d], config_duration_ms[%d], cmdId[%d]\n", status, pTask, thread, tgid, pid, duration, iwcCommand); } else { CMDQ_LOG ("[SEC]<--SEC_SUBMIT: err[%d], pTask[0x%p], THR[%d], tgid[%d:%d], config_duration_ms[%d], cmdId[%d]\n", status, pTask, thread, tgid, pid, duration, iwcCommand); } return status; }