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 */
}
Beispiel #2
0
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;
}
Beispiel #3
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 */
}
Beispiel #6
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
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
}
Beispiel #15
0
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;
}
Beispiel #16
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;
}
Beispiel #17
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;
}
Beispiel #20
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;
}
Beispiel #22
0
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;
}