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 int cmdq_release(struct inode *pInode, struct file *pFile) { cmdqFileNodeStruct *pNode; unsigned long flags; CMDQ_VERBOSE("CMDQ driver release fd=%p begin\n", pFile); pNode = (cmdqFileNodeStruct *) pFile->private_data; if (NULL == pNode) { CMDQ_ERR("CMDQ file node NULL\n"); return -EFAULT; } spin_lock_irqsave(&pNode->nodeLock, flags); /* note that we did not release CMDQ tasks */ /* issued by this file node, */ /* since their HW operation may be pending. */ spin_unlock_irqrestore(&pNode->nodeLock, flags); /* scan through tasks that created by this file node and release them */ cmdq_core_release_task_by_file_node((void *)pNode); if (NULL != pFile->private_data) { kfree(pFile->private_data); pFile->private_data = NULL; } CMDQ_VERBOSE("CMDQ driver release end\n"); return 0; }
void cmdq_virtual_enable_common_clock_locked(bool enable) { #ifdef CMDQ_PWR_AWARE if (enable) { CMDQ_VERBOSE("[CLOCK] Enable SMI & LARB0 Clock\n"); cmdq_dev_enable_clock_SMI_COMMON(enable); #ifdef CMDQ_CG_M4U_LARB0 m4u_larb0_enable("CMDQ_MDP"); #else cmdq_dev_enable_clock_SMI_LARB0(enable); #endif #ifdef CMDQ_USE_LEGACY CMDQ_VERBOSE("[CLOCK] enable MT_CG_DISP0_MUTEX_32K\n"); cmdq_dev_enable_clock_MUTEX_32K(enable); #endif } else { CMDQ_VERBOSE("[CLOCK] Disable SMI & LARB0 Clock\n"); /* disable, reverse the sequence */ #ifdef CMDQ_CG_M4U_LARB0 m4u_larb0_disable("CMDQ_MDP"); #else cmdq_dev_enable_clock_SMI_LARB0(enable); #endif cmdq_dev_enable_clock_SMI_COMMON(enable); #ifdef CMDQ_USE_LEGACY CMDQ_VERBOSE("[CLOCK] disable MT_CG_DISP0_MUTEX_32K\n"); cmdq_dev_enable_clock_MUTEX_32K(enable); #endif } #endif /* CMDQ_PWR_AWARE */ }
void cmdq_core_fix_command_desc_scenario_for_user_space_request(cmdqCommandStruct *pCommand) { 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_VERBOSE("[WARNING]fix user space request to CMDQ_SCENARIO_USER_SPACE\n"); pCommand->scenario = CMDQ_SCENARIO_USER_SPACE; } }
void cmdq_core_enable_gce_clock_locked_impl(bool enable) { #ifdef CMDQ_PWR_AWARE if (enable) { CMDQ_VERBOSE("[CLOCK] Enable CMDQ(GCE) Clock\n"); cmdq_core_enable_cmdq_clock_locked_impl(enable); } else { CMDQ_VERBOSE("[CLOCK] Disable CMDQ(GCE) Clock\n"); cmdq_core_enable_cmdq_clock_locked_impl(enable); } #endif /* CMDQ_PWR_AWARE */ }
void cmdq_virtual_enable_gce_clock_locked(bool enable) { #ifdef CMDQ_PWR_AWARE if (enable) { CMDQ_VERBOSE("[CLOCK] Enable CMDQ(GCE) Clock\n"); cmdq_dev_enable_gce_clock(enable); } else { CMDQ_VERBOSE("[CLOCK] Disable CMDQ(GCE) Clock\n"); cmdq_dev_enable_gce_clock(enable); } #endif }
int32_t cmdqRecProfileMarker(cmdqRecHandle handle, const char *tag) { #ifdef CMDQ_PROFILE_MARKER_SUPPORT int32_t status; int32_t index; cmdqBackupSlotHandle hSlot; dma_addr_t allocatedStartPA; do { allocatedStartPA = 0; status = 0; /* allocate temp slot for GCE to store timestamp info */ /* those timestamp info will copy to record strute after task execute done */ if ((0 == handle->profileMarker.count) && (0 == handle->profileMarker.hSlot)) { status = cmdqCoreAllocWriteAddress(CMDQ_MAX_PROFILE_MARKER_IN_TASK, &allocatedStartPA); if(0 > status) { CMDQ_ERR("[REC][PROF_MARKER]allocate failed, status:%d\n", status); break; } handle->profileMarker.hSlot = 0LL | (allocatedStartPA); CMDQ_VERBOSE("[REC][PROF_MARKER]update handle(%p) slot start PA:%pa(0x%llx)\n", handle, &allocatedStartPA, handle->profileMarker.hSlot); } /* insert instruciton */ index = handle->profileMarker.count; hSlot = (cmdqBackupSlotHandle)(handle->profileMarker.hSlot); if (index >= CMDQ_MAX_PROFILE_MARKER_IN_TASK) { CMDQ_ERR("[REC][PROF_MARKER]insert profile maker failed since already reach max count\n"); status = -EFAULT; break; } CMDQ_VERBOSE("[REC][PROF_MARKER]inserting profile instr, handle:%p, slot:%pa(0x%llx), index:%d, tag:%s\n", handle, &hSlot, handle->profileMarker.hSlot, index, tag); cmdqRecBackupRegisterToSlot(handle, hSlot, index, CMDQ_APXGPT2_COUNT); handle->profileMarker.tag[index] = tag; handle->profileMarker.count += 1; } while(0); return status; #else CMDQ_ERR("func:%s failed since CMDQ dosen't enable profile marker\n", __func__); return -EFAULT; #endif }
int32_t cmdq_rec_realloc_addr_metadata_buffer(cmdqRecHandle handle, const uint32_t size) { void *pNewBuf = NULL; void *pOriginalBuf = (void*)CMDQ_U32_PTR(handle->secData.addrMetadatas); const uint32_t originalSize = sizeof(cmdqSecAddrMetadataStruct) * (handle->secData.addrMetadataMaxCount); if (size <= originalSize) { return 0; } pNewBuf = kzalloc(size, GFP_KERNEL); if (NULL == pNewBuf) { CMDQ_ERR("REC: secAddrMetadata, kzalloc %d bytes addr_metadata buffer failed\n", size); return -ENOMEM; } if (pOriginalBuf && originalSize > 0) { memcpy(pNewBuf, pOriginalBuf, originalSize); } CMDQ_VERBOSE("REC: secAddrMetadata, realloc size from %d to %d bytes\n", originalSize, size); kfree(pOriginalBuf); handle->secData.addrMetadatas = (cmdqU32Ptr_t)(unsigned long)(pNewBuf); handle->secData.addrMetadataMaxCount = size / sizeof(cmdqSecAddrMetadataStruct); return 0; }
int cmdq_rec_realloc_cmd_buffer(cmdqRecHandle handle, uint32_t size) { void *pNewBuf = NULL; if (size <= handle->bufferSize) { return 0; } pNewBuf = kzalloc(size, GFP_KERNEL); if (NULL == pNewBuf) { CMDQ_ERR("REC: kzalloc %d bytes cmd_buffer failed\n", size); return -ENOMEM; } memset(pNewBuf, 0, size); if (handle->pBuffer && handle->blockSize > 0) { memcpy(pNewBuf, handle->pBuffer, handle->blockSize); } CMDQ_VERBOSE("REC: realloc size from %d to %d bytes\n", handle->bufferSize, size); kfree(handle->pBuffer); handle->pBuffer = pNewBuf; handle->bufferSize = size; return 0; }
static int cmdq_release(struct inode *pInode, struct file *pFile) { struct cmdqFileNodeStruct *pNode; unsigned long flags; int32_t index; CMDQ_VERBOSE("CMDQ driver release fd=%p begin\n", pFile); pNode = (struct cmdqFileNodeStruct *)pFile->private_data; if (NULL == pNode) { CMDQ_ERR("CMDQ file node NULL\n"); return -EFAULT; } spin_lock_irqsave(&pNode->nodeLock, flags); if (pNode->mutexFlag) { for (index = DISP_MUTEX_MDP_FIRST; index < DISP_MUTEX_MDP_FIRST + DISP_MUTEX_MDP_COUNT; index++) { if ((1 << index) & pNode->mutexFlag) cmdqMutexRelease(index); } pNode->mutexFlag = 0; } /* note that we did not release CMDQ tasks */ /* issued by this file node, */ /* since their HW operation may be pending. */ spin_unlock_irqrestore(&pNode->nodeLock, flags); /* scan through tasks that created by this file node and release them */ cmdq_core_release_task_by_file_node((void *)pNode); if (NULL != pFile->private_data) { kfree(pFile->private_data); pFile->private_data = NULL; } CMDQ_VERBOSE("CMDQ driver release end\n"); return 0; }
int32_t cmdqRecEnablePrefetch(cmdqRecHandle handle) { if (cmdq_core_should_enable_prefetch(handle->scenario)) { /* enable prefetch */ CMDQ_VERBOSE("REC: enable prefetch\n"); cmdqRecMark(handle); return true; } CMDQ_ERR("not allow enable prefetch, scenario: %d\n", handle->scenario); return -EFAULT; }
static int cmdq_open(struct inode *pInode, struct file *pFile) { cmdqFileNodeStruct *pNode; CMDQ_VERBOSE("CMDQ driver open fd=%p begin\n", pFile); pFile->private_data = kzalloc(sizeof(cmdqFileNodeStruct), GFP_KERNEL); if (NULL == pFile->private_data) { CMDQ_ERR("Can't allocate memory for CMDQ file node\n"); return -ENOMEM; } pNode = (cmdqFileNodeStruct *) pFile->private_data; pNode->userPID = current->pid; pNode->userTGID = current->tgid; INIT_LIST_HEAD(&(pNode->taskList)); spin_lock_init(&pNode->nodeLock); CMDQ_VERBOSE("CMDQ driver open end\n"); return 0; }
int32_t cmdq_sec_free_wsm_impl(uint32_t deviceId, uint8_t **ppWsm) { int32_t status = 0; enum mc_result mcRet = mc_free_wsm(deviceId, (*ppWsm)); (*ppWsm) = (MC_DRV_OK == mcRet) ? (NULL) : (*ppWsm); CMDQ_VERBOSE("_WSM_FREE: ret[0x%x], *ppWsm[0x%p]\n", mcRet, (*ppWsm)); if (MC_DRV_OK != mcRet) { CMDQ_ERR("_WSM_FREE: err[0x%x]", mcRet); status = -1; } return status; }
int32_t cmdqRecSetSecure(cmdqRecHandle handle, const bool isSecure) { if (false == isSecure) { handle->secData.isSecure= isSecure; return 0; } #ifdef CMDQ_SECURE_PATH_SUPPORT CMDQ_VERBOSE("REC: %p secure:%d\n", handle, isSecure); handle->secData.isSecure= isSecure; return 0; #else CMDQ_ERR("%s failed since not support secure path\n", __func__); return -EFAULT; #endif }
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_driver_process_command_request(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 */ cmdq_core_fix_command_scenario_for_user_space(pCommand); 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) { /* Error status print */ 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; }
int32_t cmdq_append_command(cmdqRecHandle handle, CMDQ_CODE_ENUM code, uint32_t argA, uint32_t argB) { int32_t subsys; uint32_t *pCommand; /* be careful that subsys encoding position is different among platforms */ const uint32_t subsysBit = cmdq_core_get_subsys_LSB_in_argA(); pCommand = (uint32_t *) ((uint8_t *) handle->pBuffer + handle->blockSize); if (handle->finalized) { CMDQ_ERR("Already finalized record 0x%p, cannot add more command", handle); return -EBUSY; } /* check if we have sufficient buffer size */ /* we leave a 4 instruction (4 bytes each) margin. */ if ((handle->blockSize + 32) >= handle->bufferSize) { if (0 != cmdq_rec_realloc_cmd_buffer(handle, handle->bufferSize * 2)) { return -ENOMEM; } } /* force insert MARKER if prefetch memory is full */ /* GCE deadlocks if we don't do so */ if (CMDQ_CODE_EOC != code && cmdq_core_should_enable_prefetch(handle->scenario)) { if (handle->prefetchCount >= CMDQ_MAX_PREFETCH_INSTUCTION) { /* Mark END of prefetch section */ cmdqRecMark(handle); /* BEGING of next prefetch section */ cmdqRecMark(handle); } else { ++handle->prefetchCount; } } /* we must re-calculate current PC because we may already insert MARKER inst. */ pCommand = (uint32_t *) ((uint8_t *) handle->pBuffer + handle->blockSize); CMDQ_VERBOSE("REC: 0x%p CMD: 0x%p, op: 0x%02x, argA: 0x%08x, argB: 0x%08x\n", handle, pCommand, code, argA, argB); switch (code) { case CMDQ_CODE_READ: /* argA is the HW register address to read from */ subsys = cmdq_subsys_from_phys_addr(argA); /* argB is the register id to read into */ /* bit 54: argB type, 1 for GPR */ *pCommand++ = argB; *pCommand++ = (CMDQ_CODE_READ << 24) | (argA & 0xffff) | ((subsys & 0x1f) << subsysBit) | (2 << 21); break; case CMDQ_CODE_MOVE: *pCommand++ = argB; *pCommand++ = CMDQ_CODE_MOVE << 24 | (argA & 0xffffff); break; case CMDQ_CODE_WRITE: subsys = cmdq_subsys_from_phys_addr(argA); if (-1 == subsys) { CMDQ_ERR("REC: Unsupported memory base address 0x%08x\n", argA); return -EFAULT; } *pCommand++ = argB; *pCommand++ = (CMDQ_CODE_WRITE << 24) | (argA & 0x0FFFF) | ((subsys & 0x01F) << subsysBit); break; case CMDQ_CODE_POLL: subsys = cmdq_subsys_from_phys_addr(argA); if (-1 == subsys) { CMDQ_ERR("REC: Unsupported memory base address 0x%08x\n", argA); return -EFAULT; } *pCommand++ = argB; *pCommand++ = (CMDQ_CODE_POLL << 24) | (argA & 0x0FFFF) | ((subsys & 0x01F) << subsysBit); break; case CMDQ_CODE_JUMP: *pCommand++ = argB; *pCommand++ = (CMDQ_CODE_JUMP << 24) | (argA & 0x0FFFFFF); break; case CMDQ_CODE_WFE: /* bit 0-11: wait_value, 1 */ /* bit 15: to_wait, true */ /* bit 31: to_update, true */ /* bit 16-27: update_value, 0 */ *pCommand++ = ((1 << 31) | (1 << 15) | 1); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_SET_TOKEN: /* this is actually WFE(SYNC) but with different parameter */ /* interpretation */ /* bit 15: to_wait, false */ /* bit 31: to_update, true */ /* bit 16-27: update_value, 1 */ *pCommand++ = ((1 << 31) | (1 << 16)); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_WAIT_NO_CLEAR: /* bit 0-11: wait_value, 1 */ /* bit 15: to_wait, true */ /* bit 31: to_update, false */ *pCommand++ = ((0 << 31) | (1 << 15) | 1); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_CLEAR_TOKEN: /* this is actually WFE(SYNC) but with different parameter */ /* interpretation */ /* bit 15: to_wait, false */ /* bit 31: to_update, true */ /* bit 16-27: update_value, 0 */ *pCommand++ = ((1 << 31) | (0 << 16)); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_EOC: *pCommand++ = argB; *pCommand++ = (CMDQ_CODE_EOC << 24) | (argA & 0x0FFFFFF); break; case CMDQ_CODE_RAW: *pCommand++ = argB; *pCommand++ = argA; break; default: return -EFAULT; } handle->blockSize += 8; return 0; }
int32_t cmdq_append_command(cmdqRecHandle handle, CMDQ_CODE_ENUM code, uint32_t argA, uint32_t argB, uint32_t argAType, uint32_t argBType) { int32_t subsys; uint32_t *pCommand; /* be careful that subsys encoding position is different among platforms */ const uint32_t subsysBit = cmdq_core_get_subsys_LSB_in_argA(); pCommand = (uint32_t *) ((uint8_t *) handle->pBuffer + handle->blockSize); if (handle->finalized) { CMDQ_ERR("Already finalized record 0x%p, cannot add more command", handle); return -EBUSY; } /* check if we have sufficient buffer size */ /* we leave a 4 instruction (4 bytes each) margin. */ if ((handle->blockSize + 32) >= handle->bufferSize) { if (0 != cmdq_rec_realloc_cmd_buffer(handle, handle->bufferSize * 2)) { return -ENOMEM; } } /* force insert MARKER if prefetch memory is full */ /* GCE deadlocks if we don't do so */ if (CMDQ_CODE_EOC != code && cmdq_core_should_enable_prefetch(handle->scenario)) { if (handle->prefetchCount >= CMDQ_MAX_PREFETCH_INSTUCTION) { CMDQ_ERR("prefetchCount(%d) > MAX_PREFETCH_INSTUCTION, force insert disable prefetch marker\n", handle->prefetchCount); /* Mark END of prefetch section */ cmdqRecDisablePrefetch(handle); /* BEGING of next prefetch section */ cmdqRecMark(handle); } else { /* prefetch enabled marker exist */ if (1 <= handle->prefetchCount) { ++handle->prefetchCount; CMDQ_VERBOSE("handle->prefetchCount: %d, %s, %d\n", handle->prefetchCount, __func__, __LINE__); } } } /* we must re-calculate current PC because we may already insert MARKER inst. */ pCommand = (uint32_t *) ((uint8_t *) handle->pBuffer + handle->blockSize); CMDQ_VERBOSE("REC: 0x%p CMD: 0x%p, op: 0x%02x, argA: 0x%08x, argB: 0x%08x\n", handle, pCommand, code, argA, argB); if (CMDQ_CODE_READ == code || CMDQ_CODE_WRITE == code || CMDQ_CODE_POLL == code){ /* Because read/write/poll have similar format, handle them together*/ return cmdq_append_wpr_command(handle, code, argA, argB, argAType, argBType); } switch (code) { case CMDQ_CODE_MOVE: *pCommand++ = argB; *pCommand++ = CMDQ_CODE_MOVE << 24 | (argA & 0xffffff); break; case CMDQ_CODE_JUMP: *pCommand++ = argB; *pCommand++ = (CMDQ_CODE_JUMP << 24) | (argA & 0x0FFFFFF); break; case CMDQ_CODE_WFE: /* bit 0-11: wait_value, 1 */ /* bit 15: to_wait, true */ /* bit 31: to_update, true */ /* bit 16-27: update_value, 0 */ *pCommand++ = ((1 << 31) | (1 << 15) | 1); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_SET_TOKEN: /* this is actually WFE(SYNC) but with different parameter */ /* interpretation */ /* bit 15: to_wait, false */ /* bit 31: to_update, true */ /* bit 16-27: update_value, 1 */ *pCommand++ = ((1 << 31) | (1 << 16)); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_WAIT_NO_CLEAR: /* bit 0-11: wait_value, 1 */ /* bit 15: to_wait, true */ /* bit 31: to_update, false */ *pCommand++ = ((0 << 31) | (1 << 15) | 1); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_CLEAR_TOKEN: /* this is actually WFE(SYNC) but with different parameter */ /* interpretation */ /* bit 15: to_wait, false */ /* bit 31: to_update, true */ /* bit 16-27: update_value, 0 */ *pCommand++ = ((1 << 31) | (0 << 16)); *pCommand++ = (CMDQ_CODE_WFE << 24) | argA; break; case CMDQ_CODE_EOC: *pCommand++ = argB; *pCommand++ = (CMDQ_CODE_EOC << 24) | (argA & 0x0FFFFFF); break; case CMDQ_CODE_RAW: *pCommand++ = argB; *pCommand++ = argA; break; default: return -EFAULT; } handle->blockSize += CMDQ_INST_SIZE; return 0; }
/** * centralize the write/polling/read command for APB and GPR handle * this function must be called inside cmdq_append_command * because we ignore buffer and pre-fetch check here. * Parameter: * same as cmdq_append_command * Return: * same as cmdq_append_command */ static int32_t cmdq_append_wpr_command(cmdqRecHandle handle, CMDQ_CODE_ENUM code, uint32_t argA, uint32_t argB, uint32_t argAType, uint32_t argBType) { int32_t subsys; uint32_t *pCommand; bool bUseGPR = false; /* use new argA to present final inserted argA*/ uint32_t newArgA; uint32_t newArgAType = argAType; uint32_t argType = 0; /* be careful that subsys encoding position is different among platforms */ const uint32_t subsysBit = cmdq_core_get_subsys_LSB_in_argA(); pCommand = (uint32_t *) ((uint8_t *) handle->pBuffer + handle->blockSize); if (CMDQ_CODE_READ != code && CMDQ_CODE_WRITE != code && CMDQ_CODE_POLL != code){ CMDQ_ERR("Record 0x%p, flow error, should not append comment in wpr API", handle); return -EFAULT; } /* we must re-calculate current PC at first. */ pCommand = (uint32_t *) ((uint8_t *) handle->pBuffer + handle->blockSize); CMDQ_VERBOSE("REC: 0x%p CMD: 0x%p, op: 0x%02x\n", handle, pCommand, code); CMDQ_VERBOSE("REC: 0x%p CMD: argA: 0x%08x, argB: 0x%08x, argAType: %d, argBType: %d\n", handle, argA, argB, argAType, argBType); if (0 == argAType){ /* argA is the HW register address to read from */ subsys = cmdq_subsys_from_phys_addr(argA); if (CMDQ_SPECIAL_SUBSYS_ADDR == subsys){ #ifdef CMDQ_GPR_SUPPORT bUseGPR = true; CMDQ_MSG("REC: Special handle memory base address 0x%08x\n", argA); /* Wait and clear for GPR mutex token to enter mutex*/ *pCommand++ = ((1 << 31) | (1 << 15) | 1); *pCommand++ = (CMDQ_CODE_WFE << 24) | CMDQ_SYNC_TOKEN_GPR_SET_4; handle->blockSize += CMDQ_INST_SIZE; /* Move extra handle APB address to GPR*/ *pCommand++ = argA; *pCommand++ = (CMDQ_CODE_MOVE << 24) | ((CMDQ_DATA_REG_DEBUG & 0x1f) << 16) | (4 << 21); handle->blockSize += CMDQ_INST_SIZE; /* change final argA to GPR */ newArgA = ((CMDQ_DATA_REG_DEBUG & 0x1f) << 16); if (argA & 0x1){ /* MASK case, set final bit to 1*/ newArgA = newArgA | 0x1; } /* change argA type to 1*/ newArgAType = 1; #else CMDQ_ERR("func:%s failed since CMDQ dosen't support GPR\n", __func__); return -EFAULT; #endif }else if (0 == argAType && 0 > subsys){ CMDQ_ERR("REC: Unsupported memory base address 0x%08x\n", argA); return -EFAULT; }else{ /* compose final argA according to subsys table */ newArgA = (argA & 0xffff) | ((subsys & 0x1f) << subsysBit); } }else{ /* compose final argA according GPR value */ newArgA = ((argA & 0x1f) << 16); } argType = (newArgAType << 2) | (argBType << 1); /* newArgA is the HW register address to access from or GPR value store the HW register address */ /* argB is the value or register id */ /* bit 55: argA type, 1 for GPR */ /* bit 54: argB type, 1 for GPR */ /* argType: ('newArgAType', 'argBType', '0') */ *pCommand++ = argB; *pCommand++ = (code << 24) | newArgA | (argType << 21); handle->blockSize += CMDQ_INST_SIZE; if (bUseGPR) { /* Set for GPR mutex token to leave mutex*/ *pCommand++ = ((1 << 31) | (1 << 16)); *pCommand++ = (CMDQ_CODE_WFE << 24) | CMDQ_SYNC_TOKEN_GPR_SET_4; handle->blockSize += CMDQ_INST_SIZE; } return 0; }
int32_t cmdq_sec_init_session_unlocked(const struct mc_uuid_t *uuid, uint8_t **ppWsm, uint32_t wsmSize, struct mc_session_handle *pSessionHandle, CMDQ_IWC_STATE_ENUM *pIwcState, uint32_t *openMobicoreByOther) { int32_t openRet = 0; int32_t status = 0; uint32_t deviceId = MC_DEVICE_ID_DEFAULT; CMDQ_MSG("[SEC]-->SESSION_INIT: iwcState[%d]\n", (*pIwcState)); do { #if CMDQ_OPEN_SESSION_ONCE if (IWC_SES_OPENED <= (*pIwcState)) { CMDQ_MSG("SESSION_INIT: already opened\n"); break; } else { CMDQ_MSG("[SEC]SESSION_INIT: open new session[%d]\n", (*pIwcState)); } #endif CMDQ_VERBOSE ("[SEC]SESSION_INIT: wsmSize[%d], pSessionHandle: 0x%p\n", wsmSize, pSessionHandle); CMDQ_PROF_START("CMDQ_SEC_INIT"); /* open mobicore device */ openRet = cmdq_sec_open_mobicore_impl(deviceId); if (-EEXIST == openRet) { /* mobicore has been opened in this process context */ /* it is a ok case, so continue to execute */ status = 0; (*openMobicoreByOther) = 1; } else if (0 > openRet) { status = -1; break; } (*pIwcState) = IWC_MOBICORE_OPENED; /* allocate world shared memory */ if (0 > cmdq_sec_allocate_wsm_impl(deviceId, ppWsm, wsmSize)) { status = -1; break; } (*pIwcState) = IWC_WSM_ALLOCATED; /* open a secure session */ if (0 > cmdq_sec_open_session_impl(deviceId, uuid, (*ppWsm), wsmSize, pSessionHandle)) { status = -1; break; } (*pIwcState) = IWC_SES_OPENED; CMDQ_PROF_END("CMDQ_SEC_INIT"); } while (0); CMDQ_MSG("[SEC]<--SESSION_INIT[%d]\n", status); return status; }
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; }
int32_t cmdq_sec_fill_iwc_command_msg_unlocked(int32_t iwcCommand, void *_pTask, int32_t thread, void *_pIwc) { int32_t status; const TaskStruct *pTask = (TaskStruct *)_pTask; iwcCmdqMessage_t *pIwc; /* cmdqSecDr will insert some instr*/ const uint32_t reservedCommandSize = 4 * CMDQ_INST_SIZE; status = 0; pIwc = (iwcCmdqMessage_t *)_pIwc; /* check command size first */ if (pTask && (CMDQ_TZ_CMD_BLOCK_SIZE < (pTask->commandSize + reservedCommandSize))) { CMDQ_ERR("[SEC]SESSION_MSG: pTask %p commandSize %d > %d\n", pTask, pTask->commandSize, CMDQ_TZ_CMD_BLOCK_SIZE); return -EFAULT; } CMDQ_MSG("[SEC]-->SESSION_MSG: cmdId[%d]\n", iwcCommand); /* fill message buffer for inter world communication */ memset(pIwc, 0x0, sizeof(iwcCmdqMessage_t)); pIwc->cmd = iwcCommand; /* metadata */ pIwc->command.metadata.enginesNeedDAPC = pTask->secData.enginesNeedDAPC; pIwc->command.metadata.enginesNeedPortSecurity = pTask->secData.enginesNeedPortSecurity; if (NULL != pTask && CMDQ_INVALID_THREAD != thread) { /* basic data */ pIwc->command.scenario = pTask->scenario; pIwc->command.thread = thread; pIwc->command.priority = pTask->priority; pIwc->command.engineFlag = pTask->engineFlag; pIwc->command.commandSize = pTask->commandSize; pIwc->command.hNormalTask = 0LL | ((unsigned long) pTask); memcpy((pIwc->command.pVABase), (pTask->pVABase), (pTask->commandSize)); /* cookie */ pIwc->command.waitCookie = pTask->secData.waitCookie; pIwc->command.resetExecCnt = pTask->secData.resetExecCnt; CMDQ_MSG("[SEC]SESSION_MSG: task 0x%p, thread: %d, size: %d, bufferSize: %d, scenario:%d, flag:0x%08llx ,hNormalTask:0x%llx\n", pTask, thread, pTask->commandSize, pTask->bufferSize, pTask->scenario, pTask->engineFlag, pIwc->command.hNormalTask); CMDQ_VERBOSE("[SEC]SESSION_MSG: addrList[%d][0x%p]\n", pTask->secData.addrMetadataCount,CMDQ_U32_PTR(pTask->secData.addrMetadatas)); if (0 < pTask->secData.addrMetadataCount) { pIwc->command.metadata.addrListLength = pTask->secData.addrMetadataCount; memcpy((pIwc->command.metadata.addrList), (pTask->secData.addrMetadatas), (pTask->secData.addrMetadataCount) * sizeof(iwcCmdqAddrMetadata_t)); } /* medatada: debug config */ pIwc->debug.logLevel = (cmdq_core_should_print_msg()) ? (1) : (0); pIwc->debug.enableProfile = cmdq_core_profile_enabled(); } else { /* relase resource, or debug function will go here */ CMDQ_VERBOSE("[SEC]-->SESSION_MSG: no task, cmdId[%d]\n", iwcCommand); pIwc->command.commandSize = 0; pIwc->command.metadata.addrListLength = 0; } CMDQ_MSG("[SEC]<--SESSION_MSG[%d]\n", status); return status; }