예제 #1
0
/**
 * videobuf_pmem_contig_user_get() - setup user space memory pointer
 * @mem: per-buffer private videobuf-contig-pmem data
 * @vb: video buffer to map
 *
 * This function validates and sets up a pointer to user space memory.
 * Only physically contiguous pfn-mapped memory is accepted.
 *
 * Returns 0 if successful.
 */
int videobuf2_pmem_contig_user_get(struct videobuf2_contig_pmem *mem,
                                   struct videobuf2_msm_offset *offset,
                                   enum videobuf2_buffer_type buffer_type,
                                   uint32_t addr_offset, int path,
                                   struct ion_client *client)
{
    unsigned long len;
    int rc = 0;
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
    unsigned long kvstart;
#endif
    unsigned int flags = 0;
    unsigned long paddr = 0;
    if (mem->phyaddr != 0)
        return 0;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
    mem->ion_handle = ion_import_fd(client, (int)mem->vaddr);
    if (IS_ERR_OR_NULL(mem->ion_handle)) {
        pr_err("%s ION import failed\n", __func__);
        return PTR_ERR(mem->ion_handle);
    }
    rc = ion_phys(client, mem->ion_handle, (ion_phys_addr_t *)&mem->phyaddr,
                  (size_t *)&len);
#elif CONFIG_ANDROID_PMEM
    rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr,
                       &kvstart, &len, &mem->file);
    if (rc < 0) {
        pr_err("%s: get_pmem_file fd %d error %d\n",
               __func__, (int)mem->vaddr, rc);
        return rc;
    }
#else
    paddr = 0;
    kvstart = 0;
#endif
    if (offset)
        mem->offset = *offset;
    else
        memset(&mem->offset, 0, sizeof(struct videobuf2_msm_offset));
    mem->path = path;
    mem->buffer_type = buffer_type;
    paddr = mem->phyaddr;
    flags = MSM_SUBSYSTEM_MAP_IOVA;
    mem->subsys_id = MSM_SUBSYSTEM_CAMERA;
    mem->msm_buffer = msm_subsystem_map_buffer(mem->phyaddr, len,
                      flags, &(mem->subsys_id), 1);
    if (IS_ERR((void *)mem->msm_buffer)) {
        pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
        ion_free(client, mem->ion_handle);
#elif CONFIG_ANDROID_PMEM
        put_pmem_file(mem->file);
#endif
        return PTR_ERR((void *)mem->msm_buffer);
    }
    paddr = mem->msm_buffer->iova[0];
    mem->mapped_phyaddr = paddr + addr_offset;
    mem->addr_offset = addr_offset;
    return rc;
}
static int register_memory(void)
{
	int			result;
	unsigned long		paddr;
	unsigned long		kvaddr;
	unsigned long		mem_len;

	mutex_lock(&acdb_data.acdb_mutex);
	acdb_data.ion_client =
		msm_ion_client_create(UINT_MAX, "audio_acdb_client");
	if (IS_ERR_OR_NULL(acdb_data.ion_client)) {
		pr_err("%s: Could not register ION client!!!\n", __func__);
		result = PTR_ERR(acdb_data.ion_client);
		goto err;
	}

	acdb_data.ion_handle = ion_import_fd(acdb_data.ion_client,
		atomic_read(&acdb_data.map_handle));
	if (IS_ERR_OR_NULL(acdb_data.ion_handle)) {
		pr_err("%s: Could not import map handle!!!\n", __func__);
		result = PTR_ERR(acdb_data.ion_client);
		goto err_ion_client;
	}

	result = ion_phys(acdb_data.ion_client, acdb_data.ion_handle,
				&paddr, (size_t *)&mem_len);
	if (result != 0) {
		pr_err("%s: Could not get phys addr!!!\n", __func__);
		goto err_ion_handle;
	}

	kvaddr = (unsigned long)ion_map_kernel(acdb_data.ion_client,
		acdb_data.ion_handle, 0);
	if (IS_ERR_OR_NULL(&kvaddr)) {
		pr_err("%s: Could not get kernel virt addr!!!\n", __func__);
		result = -EINVAL;
		goto err_ion_handle;
	}
	mutex_unlock(&acdb_data.acdb_mutex);

	atomic64_set(&acdb_data.paddr, paddr);
	atomic64_set(&acdb_data.kvaddr, kvaddr);
	atomic64_set(&acdb_data.mem_len, mem_len);
	pr_debug("%s done! paddr = 0x%lx, "
		"kvaddr = 0x%lx, len = x%lx\n",
		 __func__,
		(long)atomic64_read(&acdb_data.paddr),
		(long)atomic64_read(&acdb_data.kvaddr),
		(long)atomic64_read(&acdb_data.mem_len));

	return result;
err_ion_handle:
	ion_free(acdb_data.ion_client, acdb_data.ion_handle);
err_ion_client:
	ion_client_destroy(acdb_data.ion_client);
err:
	atomic64_set(&acdb_data.mem_len, 0);
	mutex_unlock(&acdb_data.acdb_mutex);
	return result;
}
int get_phys_addr(struct vcap_dev *dev, struct vb2_queue *q,
				  struct v4l2_buffer *b)
{
	struct vb2_buffer *vb;
	struct vcap_buffer *buf;
	unsigned long len, offset;
	int rc;

	if (q->fileio) {
		dprintk(1, "%s: file io in progress\n", __func__);
		return -EBUSY;
	}

	if (b->type != q->type) {
		dprintk(1, "%s: invalid buffer type\n", __func__);
		return -EINVAL;
	}

	if (b->index >= q->num_buffers) {
		dprintk(1, "%s: buffer index out of range\n", __func__);
		return -EINVAL;
	}

	vb = q->bufs[b->index];
	if (NULL == vb) {
		dprintk(1, "%s: buffer is NULL\n", __func__);
		return -EINVAL;
	}

	if (vb->state != VB2_BUF_STATE_DEQUEUED) {
		dprintk(1, "%s: buffer already in use\n", __func__);
		return -EINVAL;
	}

	buf = container_of(vb, struct vcap_buffer, vb);

	buf->ion_handle = ion_import_fd(dev->ion_client, b->m.userptr);
	if (IS_ERR((void *)buf->ion_handle)) {
		pr_err("%s: Could not alloc memory\n", __func__);
		buf->ion_handle = NULL;
		return -ENOMEM;
	}
	rc = ion_phys(dev->ion_client, buf->ion_handle,
			&buf->paddr, (size_t *)&len);
	if (rc < 0) {
		pr_err("%s: Could not get phys addr\n", __func__);
		ion_free(dev->ion_client, buf->ion_handle);
		buf->ion_handle = NULL;
		return -EFAULT;
	}

	offset = b->reserved;
	buf->paddr += offset;
	return 0;
}
예제 #4
0
/**
 * videobuf_pmem_contig_user_get() - setup user space memory pointer
 * @mem: per-buffer private videobuf-contig-pmem data
 * @vb: video buffer to map
 *
 * This function validates and sets up a pointer to user space memory.
 * Only physically contiguous pfn-mapped memory is accepted.
 *
 * Returns 0 if successful.
 */
int videobuf2_pmem_contig_user_get(struct videobuf2_contig_pmem *mem,
					struct videobuf2_msm_offset *offset,
					enum videobuf2_buffer_type buffer_type,
					uint32_t addr_offset, int path,
					struct ion_client *client)
{
	unsigned long len;
	int rc = 0;
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
	unsigned long kvstart;
#endif
	unsigned long paddr = 0;
	if (mem->phyaddr != 0)
		return 0;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
	mem->ion_handle = ion_import_fd(client, (int)mem->vaddr);
	if (IS_ERR_OR_NULL(mem->ion_handle)) {
		pr_err("%s ION import failed\n", __func__);
		return PTR_ERR(mem->ion_handle);
	}
	rc = ion_map_iommu(client, mem->ion_handle, CAMERA_DOMAIN, GEN_POOL,
		SZ_4K, 0, (unsigned long *)&mem->phyaddr, &len, UNCACHED, 0);
	if (rc < 0)
		ion_free(client, mem->ion_handle);
	rc = ion_handle_get_flags(client, mem->ion_handle, &mem->ion_flags);
	mem->kernel_vaddr = ion_map_kernel(client,
		mem->ion_handle, mem->ion_flags);
#elif CONFIG_ANDROID_PMEM
	rc = get_pmem_file((int)mem->vaddr, (unsigned long *)&mem->phyaddr,
					&kvstart, &len, &mem->file);
	if (rc < 0) {
		pr_err("%s: get_pmem_file fd %d error %d\n",
					__func__, (int)mem->vaddr, rc);
		return rc;
	}
#else
	paddr = 0;
	kvstart = 0;
#endif
	if (offset)
		mem->offset = *offset;
	else
		memset(&mem->offset, 0, sizeof(struct videobuf2_msm_offset));
	mem->path = path;
	mem->buffer_type = buffer_type;
	paddr = mem->phyaddr;
	mem->mapped_phyaddr = paddr + addr_offset;
	mem->addr_offset = addr_offset;
	return rc;
}
예제 #5
0
static int ion_user_to_kernel(struct smem_client *client,
			int fd, u32 offset, struct msm_smem *mem)
{
	struct ion_handle *hndl;
	unsigned long ionflag;
	size_t len;
	int rc = 0;
	hndl = ion_import_fd(client->clnt, fd);
	if (IS_ERR_OR_NULL(hndl)) {
		pr_err("Failed to get handle: %p, %d, %d, %p\n",
				client, fd, offset, hndl);
		rc = -ENOMEM;
		goto fail_import_fd;
	}
	rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
	if (rc) {
		pr_err("Failed to get ion flags: %d", rc);
		goto fail_map;
	}
	rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
	if (rc) {
		pr_err("Failed to get physical address\n");
		goto fail_map;
	}
	mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
	if (!mem->kvaddr) {
		pr_err("Failed to map shared mem in kernel\n");
		rc = -EIO;
		goto fail_map;
	}

	mem->kvaddr += offset;
	mem->paddr += offset;
	mem->mem_type = client->mem_type;
	mem->smem_priv = hndl;
	mem->device_addr = mem->paddr;
	mem->size = len;
	return rc;
fail_map:
	ion_free(client->clnt, hndl);
fail_import_fd:
	return rc;
}
uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
				struct ion_handle **ionhandle)
{
	unsigned long paddr;
	unsigned long size;
	int rc;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
	*ionhandle = ion_import_fd(gemini_client, fd);
	if (IS_ERR_OR_NULL(*ionhandle))
		return 0;

	rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
			SZ_4K, 0, &paddr, (unsigned long *)&size, UNCACHED, 0);
#elif CONFIG_ANDROID_PMEM
	unsigned long kvstart;
	rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
#else
	rc = 0;
	paddr = 0;
	size = 0;
#endif
	if (rc < 0) {
		GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
			rc);
		goto error1;
	}

	/* validate user input */
	if (len > size) {
		GMN_PR_ERR("%s: invalid offset + len\n", __func__);
		goto error1;
	}

	return paddr;
error1:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
	ion_free(gemini_client, *ionhandle);
#endif
	return 0;
}
/*
 * IOCTL operation; Import fd to  UMP memory
 */
int ump_ion_import_wrapper(u32 __user * argument, struct ump_session_data  * session_data)
{
	_ump_uk_ion_import_s user_interaction;
	ump_dd_handle *ump_handle;
	ump_dd_physical_block * blocks;
	unsigned long num_blocks;
	struct ion_handle *ion_hnd;
	struct scatterlist *sg;
	struct scatterlist *sg_ion;
	unsigned long i = 0;

	ump_session_memory_list_element * session_memory_element = NULL;
	if (ion_client_ump==NULL)
	    ion_client_ump = ion_client_create(ion_exynos, -1, "ump");

	/* Sanity check input parameters */
	if (NULL == argument || NULL == session_data)
	{
		MSG_ERR(("NULL parameter in ump_ioctl_allocate()\n"));
		return -ENOTTY;
	}

	/* Copy the user space memory to kernel space (so we safely can read it) */
	if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction)))
	{
		MSG_ERR(("copy_from_user() in ump_ioctl_allocate()\n"));
		return -EFAULT;
	}

	user_interaction.ctx = (void *) session_data;

	/* translate fd to secure ID*/
	ion_hnd = ion_import_fd(ion_client_ump, user_interaction.ion_fd);
	sg_ion = ion_map_dma(ion_client_ump,ion_hnd);

	blocks = (ump_dd_physical_block*)_mali_osk_malloc(sizeof(ump_dd_physical_block)*1024);

	if (NULL == blocks) {
		MSG_ERR(("Failed to allocate blocks in ump_ioctl_allocate()\n"));
		return -ENOMEM;
	}

	sg = sg_ion;
	do {
		blocks[i].addr = sg_phys(sg);
		blocks[i].size = sg_dma_len(sg);
		i++;
		if (i>=1024) {
			_mali_osk_free(blocks);
			MSG_ERR(("ion_import fail() in ump_ioctl_allocate()\n"));
			return -EFAULT;
		}
		sg = sg_next(sg);
	} while(sg);

	num_blocks = i;

	/* Initialize the session_memory_element, and add it to the session object */
	session_memory_element = _mali_osk_calloc( 1, sizeof(ump_session_memory_list_element));

	if (NULL == session_memory_element)
	{
		_mali_osk_free(blocks);
		DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n"));
		return -EFAULT;
	}

	ump_handle = ump_dd_handle_create_from_phys_blocks(blocks, num_blocks);
	if (UMP_DD_HANDLE_INVALID == ump_handle)
	{
		_mali_osk_free(session_memory_element);
		_mali_osk_free(blocks);
		DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n"));
		return -EFAULT;
	}

	session_memory_element->mem = (ump_dd_mem*)ump_handle;
	_mali_osk_mutex_wait(session_data->lock);
	_mali_osk_list_add(&(session_memory_element->list), &(session_data->list_head_session_memory_list));
	_mali_osk_mutex_signal(session_data->lock);
	ion_unmap_dma(ion_client_ump,ion_hnd);
	ion_free(ion_client_ump, ion_hnd);

	_mali_osk_free(blocks);

	user_interaction.secure_id = ump_dd_secure_id_get(ump_handle);
	user_interaction.size = ump_dd_size_get(ump_handle);
	user_interaction.ctx = NULL;

	if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction)))
	{
		/* If the copy fails then we should release the memory. We can use the IOCTL release to accomplish this */

		MSG_ERR(("copy_to_user() failed in ump_ioctl_allocate()\n"));

		return -EFAULT;
	}
	return 0; /* success */
}
예제 #8
0
static int msm_pmem_table_add(struct hlist_head *ptype,
	struct msm_pmem_info *info, struct ion_client *client)
{
	unsigned long paddr;
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
	unsigned long kvstart;
	struct file *file;
#endif
	int rc = -ENOMEM;

	unsigned long len;
	struct msm_pmem_region *region;

	region = kmalloc(sizeof(struct msm_pmem_region), GFP_KERNEL);
	if (!region)
		goto out;
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
	region->handle = ion_import_fd(client, info->fd);
	if (IS_ERR_OR_NULL(region->handle))
		goto out1;
	if (ion_map_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL,
				  SZ_4K, 0, &paddr, &len, UNCACHED, 0) < 0)
		goto out2;
#elif CONFIG_ANDROID_PMEM
	rc = get_pmem_file(info->fd, &paddr, &kvstart, &len, &file);
	if (rc < 0) {
		pr_err("%s: get_pmem_file fd %d error %d\n",
				__func__, info->fd, rc);
		goto out1;
	}
	region->file = file;
#else
	paddr = 0;
	file = NULL;
	kvstart = 0;
#endif
	if (!info->len)
		info->len = len;
	rc = check_pmem_info(info, len);
	if (rc < 0)
		goto out3;
	paddr += info->offset;
	len = info->len;

	if (check_overlap(ptype, paddr, len) < 0) {
		rc = -EINVAL;
		goto out3;
	}

	CDBG("%s: type %d, active flag %d, paddr 0x%lx, vaddr 0x%lx\n",
		__func__, info->type, info->active, paddr,
		(unsigned long)info->vaddr);

	INIT_HLIST_NODE(&region->list);
	region->paddr = paddr;
	region->len = len;
	memcpy(&region->info, info, sizeof(region->info));
	D("%s Adding region to list with type %d\n", __func__,
						region->info.type);
	D("%s pmem_stats address is 0x%p\n", __func__, ptype);
	hlist_add_head(&(region->list), ptype);

	return 0;
out3:
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
	ion_unmap_iommu(client, region->handle, CAMERA_DOMAIN, GEN_POOL);
#endif
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
out2:
	ion_free(client, region->handle);
#elif CONFIG_ANDROID_PMEM
	put_pmem_file(region->file);
#endif
out1:
	kfree(region);
out:
	return rc;
}
예제 #9
0
PVRSRV_ERROR IonImportBufferAndAquirePhysAddr(IMG_HANDLE hIonDev,
											  IMG_HANDLE hIonFD,
											  IMG_UINT32 *pui32PageCount,
											  IMG_SYS_PHYADDR **ppasSysPhysAddr,
											  IMG_PVOID *ppvKernAddr,
											  IMG_HANDLE *phPriv)
{
	struct ion_client *psIonClient = hIonDev;
	struct ion_handle *psIonHandle;
	struct scatterlist *psScatterList;
	struct scatterlist *psTemp;
	IMG_SYS_PHYADDR *pasSysPhysAddr = NULL;
	ION_IMPORT_DATA *psImportData;
	PVRSRV_ERROR eError;
	IMG_UINT32 ui32PageCount = 0;
	IMG_UINT32 i;
	IMG_PVOID pvKernAddr;
	int fd = (int) hIonFD;

	psImportData = kmalloc(sizeof(ION_IMPORT_DATA), GFP_KERNEL);
	if (psImportData == NULL)
	{
		return PVRSRV_ERROR_OUT_OF_MEMORY;
	}

	/* Get the buffer handle */
	psIonHandle = ion_import_fd(psIonClient, fd);
	if (psIonHandle == IMG_NULL)
	{
		eError = PVRSRV_ERROR_BAD_MAPPING;
		goto exitFailImport;
	}

	/* Create data for free callback */
	psImportData->psIonClient = psIonClient;
	psImportData->psIonHandle = psIonHandle;	

	psScatterList = ion_map_dma(psIonClient, psIonHandle);
	if (psScatterList == NULL)
	{
		eError = PVRSRV_ERROR_INVALID_PARAMS;
		goto exitFailMap;
	}

	/*
		We do a two pass process, 1st workout how many pages there
		are, 2nd fill in the data.
	*/
	for (i=0;i<2;i++)
	{
		psTemp = psScatterList;
		if (i == 1)
		{
			pasSysPhysAddr = kmalloc(sizeof(IMG_SYS_PHYADDR) * ui32PageCount, GFP_KERNEL);
			if (pasSysPhysAddr == NULL)
			{
				eError = PVRSRV_ERROR_OUT_OF_MEMORY;
				goto exitFailAlloc;
			}
			ui32PageCount = 0;	/* Reset the page count a we use if for the index */
		}

		while(psTemp)
		{
			IMG_UINT32 j;

			for (j=0;j<psTemp->length;j+=PAGE_SIZE)
			{
				if (i == 1)
				{
					/* Pass 2: Get the page data */
					pasSysPhysAddr[ui32PageCount].uiAddr = sg_phys(psTemp);
				}
				ui32PageCount++;
			}
			psTemp = sg_next(psTemp);
		}
	}

	pvKernAddr = ion_map_kernel(psIonClient, psIonHandle);
	if (IS_ERR(pvKernAddr))
	{
		pvKernAddr = IMG_NULL;
	}

	psImportData->pvKernAddr = pvKernAddr;

	*ppvKernAddr = pvKernAddr;
	*pui32PageCount = ui32PageCount;
	*ppasSysPhysAddr = pasSysPhysAddr;
	*phPriv = psImportData;
	return PVRSRV_OK;

exitFailAlloc:
	ion_unmap_dma(psIonClient, psIonHandle);
exitFailMap:
	ion_free(psIonClient, psIonHandle);
exitFailImport:
	kfree(psImportData);
	return eError;
}
static long tf_device_ioctl(struct file *file, unsigned int ioctl_num,
	unsigned long ioctl_param)
{
	int result = S_SUCCESS;
	struct tf_connection *connection;
	union tf_command command;
	struct tf_command_header header;
	union tf_answer answer;
	u32 command_size;
	u32 answer_size;
	void *user_answer;

	dprintk(KERN_INFO "tf_device_ioctl(%p, %u, %p)\n",
		file, ioctl_num, (void *) ioctl_param);

	switch (ioctl_num) {
	case IOCTL_TF_GET_VERSION:
		/* ioctl is asking for the driver interface version */
		result = TF_DRIVER_INTERFACE_VERSION;
		goto exit;

#ifdef CONFIG_TF_ION
	case IOCTL_TF_ION_REGISTER: {
		int ion_register;
		/* ioctl is asking to register an ion handle */
		if (copy_from_user(&ion_register,
				(int *) ioctl_param,
				sizeof(int))) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"copy_from_user failed\n",
				file);
			result = -EFAULT;
			goto exit;
		}

		connection = tf_conn_from_file(file);
		BUG_ON(connection == NULL);

		/* Initialize ION connection */
		if (connection->ion_client == NULL) {
			connection->ion_client = ion_client_create(
						omap_ion_device,
						(1 << ION_HEAP_TYPE_CARVEOUT),
						"smc");
		}

		if (connection->ion_client == NULL) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"unable to create ion client\n",
				file);
			result = -EFAULT;
			goto exit;
		}

		/*
		 * TODO: We should use a reference count on this handle in order
		 * to not unregistered it while using it.
		 */
	       return (long)ion_import_fd(connection->ion_client, ion_register);
	}

	case IOCTL_TF_ION_UNREGISTER: {
		int ion_register;
		/* ioctl is asking to unregister an ion handle */

		if (copy_from_user(&ion_register,
				(int *) ioctl_param,
				sizeof(int))) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"copy_from_user failed\n",
				file);
			result = -EFAULT;
			goto exit;
		}

		connection = tf_conn_from_file(file);
		BUG_ON(connection == NULL);

		if (connection->ion_client == NULL) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"ion client does not exist\n",
				file);
			result = -EFAULT;
			goto exit;
		}

		ion_free(connection->ion_client,
			(struct ion_handle *) ion_register);

		return S_SUCCESS;
	}
#endif

	case IOCTL_TF_EXCHANGE:
		/*
		 * ioctl is asking to perform a message exchange with the Secure
		 * Module
		 */

		/*
		 * Make a local copy of the data from the user application
		 * This routine checks the data is readable
		 *
		 * Get the header first.
		 */
		if (copy_from_user(&header,
				(struct tf_command_header *)ioctl_param,
				sizeof(struct tf_command_header))) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"Cannot access ioctl parameter %p\n",
				file, (void *) ioctl_param);
			result = -EFAULT;
			goto exit;
		}

		/* size in words of u32 */
		command_size = header.message_size +
			sizeof(struct tf_command_header)/sizeof(u32);
		if (command_size > sizeof(command)/sizeof(u32)) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"Buffer overflow: too many bytes to copy %d\n",
				file, command_size);
			result = -EFAULT;
			goto exit;
		}

		if (copy_from_user(&command,
				(union tf_command *)ioctl_param,
				command_size * sizeof(u32))) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"Cannot access ioctl parameter %p\n",
				file, (void *) ioctl_param);
			result = -EFAULT;
			goto exit;
		}

		connection = tf_conn_from_file(file);
		BUG_ON(connection == NULL);

		/*
		 * The answer memory space address is in the operation_id field
		 */
		user_answer = (void *) command.header.operation_id;

		atomic_inc(&(connection->pending_op_count));

		dprintk(KERN_WARNING "tf_device_ioctl(%p): "
			"Sending message type  0x%08x\n",
			file, command.header.message_type);

		switch (command.header.message_type) {
		case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION:
			result = tf_open_client_session(connection,
				&command, &answer);
			break;

		case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION:
			result = tf_close_client_session(connection,
				&command, &answer);
			break;

		case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY:
			result = tf_register_shared_memory(connection,
				&command, &answer);
			break;

		case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY:
			result = tf_release_shared_memory(connection,
				&command, &answer);
			break;

		case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND:
			result = tf_invoke_client_command(connection,
				&command, &answer);
			break;

		case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND:
			result = tf_cancel_client_command(connection,
				&command, &answer);
			break;

		default:
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"Incorrect message type (0x%08x)!\n",
				connection, command.header.message_type);
			result = -EOPNOTSUPP;
			break;
		}

		atomic_dec(&(connection->pending_op_count));

		if (result != 0) {
			dprintk(KERN_WARNING "tf_device_ioctl(%p): "
				"Operation returning error code 0x%08x)!\n",
				file, result);
			goto exit;
		}

		/*
		 * Copy the answer back to the user space application.
		 * The driver does not check this field, only copy back to user
		 * space the data handed over by Secure World
		 */
		answer_size = answer.header.message_size +
			sizeof(struct tf_answer_header)/sizeof(u32);
		if (copy_to_user(user_answer,
				&answer, answer_size * sizeof(u32))) {
			dprintk(KERN_WARNING "tf_device_ioctl(%p): "
				"Failed to copy back the full command "
				"answer to %p\n", file, user_answer);
			result = -EFAULT;
			goto exit;
		}

		/* successful completion */
		dprintk(KERN_INFO "tf_device_ioctl(%p): Success\n", file);
		break;

	case  IOCTL_TF_GET_DESCRIPTION: {
		/* ioctl asking for the version information buffer */
		struct tf_version_information_buffer *pInfoBuffer;

		dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION:(%p, %u, %p)\n",
			file, ioctl_num, (void *) ioctl_param);

		pInfoBuffer =
			((struct tf_version_information_buffer *) ioctl_param);

		dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION1: "
			"driver_description=\"%64s\"\n", S_VERSION_STRING);

		if (copy_to_user(pInfoBuffer->driver_description,
				S_VERSION_STRING,
				strlen(S_VERSION_STRING) + 1)) {
			dprintk(KERN_ERR "tf_device_ioctl(%p): "
				"Fail to copy back the driver description "
				"to  %p\n",
				file, pInfoBuffer->driver_description);
			result = -EFAULT;
			goto exit;
		}

		dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION2: "
			"secure_world_description=\"%64s\"\n",
			tf_get_description(&g_tf_dev.sm));

		if (copy_to_user(pInfoBuffer->secure_world_description,
				tf_get_description(&g_tf_dev.sm),
				TF_DESCRIPTION_BUFFER_LENGTH)) {
			dprintk(KERN_WARNING "tf_device_ioctl(%p): "
				"Failed to copy back the secure world "
				"description to %p\n",
				file, pInfoBuffer->secure_world_description);
			result = -EFAULT;
			goto exit;
		}
		break;
	}

	default:
		dprintk(KERN_ERR "tf_device_ioctl(%p): "
			"Unknown IOCTL code 0x%08x!\n",
			file, ioctl_num);
		result = -EOPNOTSUPP;
		goto exit;
	}

exit:
	return result;
}
예제 #11
0
static long msm_ion_custom_ioctl(struct ion_client *client,
				unsigned int cmd,
				unsigned long arg)
{
	switch (cmd) {
	case ION_IOC_CLEAN_CACHES:
	case ION_IOC_INV_CACHES:
	case ION_IOC_CLEAN_INV_CACHES:
	{
		struct ion_flush_data data;
		unsigned long start, end;
		struct ion_handle *handle = NULL;
		int ret;

		if (copy_from_user(&data, (void __user *)arg,
					sizeof(struct ion_flush_data)))
			return -EFAULT;

		start = (unsigned long) data.vaddr;
		end = (unsigned long) data.vaddr + data.length;

		if (start && check_vaddr_bounds(start, end)) {
			pr_err("%s: virtual address %p is out of bounds\n",
				__func__, data.vaddr);
			return -EINVAL;
		}

		if (!data.handle) {
			handle = ion_import_fd(client, data.fd);
			if (IS_ERR_OR_NULL(handle)) {
				pr_info("%s: Could not import handle: %d\n",
					__func__, (int)handle);
				return -EINVAL;
			}
		}

		ret = ion_do_cache_op(client,
				data.handle ? data.handle : handle,
				data.vaddr, data.offset, data.length,
				cmd);

		if (!data.handle)
			ion_free(client, handle);

		if (ret < 0)
			return ret;

		break;

	}
	case ION_IOC_GET_FLAGS:
	{
		struct ion_flag_data data;
		int ret;
		if (copy_from_user(&data, (void __user *)arg,
					sizeof(struct ion_flag_data)))
			return -EFAULT;

		ret = ion_handle_get_flags(client, data.handle, &data.flags);
		if (ret < 0)
			return ret;
		if (copy_to_user((void __user *)arg, &data,
					sizeof(struct ion_flag_data)))
			return -EFAULT;
		break;
	}
	default:
		return -ENOTTY;
	}
	return 0;
}
예제 #12
0
PVRSRV_ERROR
PhysmemImportIon(CONNECTION_DATA *psConnection,
				 IMG_INT fd,
				 PVRSRV_MEMALLOCFLAGS_T uiFlags,
				 PMR **ppsPMRPtr,
				 IMG_DEVMEM_SIZE_T *puiSize,
				 IMG_DEVMEM_ALIGN_T *puiAlign)
{
	PMR_ION_DATA *psPrivData = IMG_NULL;
	IMG_HANDLE hPDumpAllocInfo = IMG_NULL;
	ENV_CONNECTION_DATA *psEnvConnectionData;
	PMR *psPMR = IMG_NULL;
	PMR_FLAGS_T uiPMRFlags;
    IMG_BOOL bZero;
    IMG_BOOL bPoisonOnAlloc;
    IMG_BOOL bPoisonOnFree;
	IMG_BOOL bMappingTable = IMG_TRUE;
	PVRSRV_ERROR eError;

    if (uiFlags & PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC)
    {
        bZero = IMG_TRUE;
    }
    else
    {
        bZero = IMG_FALSE;
    }

    if (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_ALLOC)
    {
        bPoisonOnAlloc = IMG_TRUE;
    }
    else
    {
        bPoisonOnAlloc = IMG_FALSE;
    }

    if (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_FREE)
    {
        bPoisonOnFree = IMG_TRUE;
    }
    else
    {
        bPoisonOnFree = IMG_FALSE;
    }

    if ((uiFlags & PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC) &&
        (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_ALLOC))
    {
        /* Zero on Alloc and Poison on Alloc are mutually exclusive */
        eError = PVRSRV_ERROR_INVALID_PARAMS;
        goto fail_params;
    }

	psPrivData = kmalloc(sizeof(*psPrivData), GFP_KERNEL);
	if (psPrivData == NULL)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto fail_privalloc;
	}

	/*
		Get the physical heap for this PMR
		
		Note:
		While we have no way to determine the type of the buffer
		we just assume that all Ion buffers are from the same
		physical heap.
	*/
	eError = PhysHeapAcquire(IonPhysHeapID(), &psPrivData->psPhysHeap);
	if (eError != PVRSRV_OK)
	{
		goto fail_physheap;
	}

	/* Get the ion client from this connection */
	psEnvConnectionData = PVRSRVConnectionPrivateData(psConnection);
	psPrivData->psIonClient = EnvDataIonClientGet(psEnvConnectionData);

	/* Get the buffer handle */
	psPrivData->psIonHandle = ion_import_fd(psPrivData->psIonClient, fd);
	if (psPrivData->psIonHandle == IMG_NULL)
	{
		/* FIXME: add ion specific error? */
		eError = PVRSRV_ERROR_BAD_MAPPING;
		goto fail_ionimport;
	}

	/*
		Note:

		We could defer the import until lock address time but we
		do it here as then we can detect any errors at import time.
		Also we need to know the ion buffer size here and there seems
		to be no other way to find that other then map the buffer for dma.
	*/
	eError = IonPhysAddrAcquire(psPrivData,
							   fd);
	if (eError != PVRSRV_OK)
	{
		goto fail_acquire;
	}

	if (bZero || bPoisonOnAlloc)
	{
		IMG_PVOID pvKernAddr;

		pvKernAddr = ion_map_kernel(psPrivData->psIonClient, psPrivData->psIonHandle);

		if (IS_ERR(pvKernAddr))
		{
			eError = PVRSRV_ERROR_PMR_NO_KERNEL_MAPPING;
			goto fail_kernelmap;
		}

		if (bZero)
		{
			memset(pvKernAddr, 0, psPrivData->uiSize);
		}
		else
		{
			_Poison(pvKernAddr,
					psPrivData->uiSize,
					_AllocPoison,
					_AllocPoisonSize);
		}

		ion_unmap_kernel(psPrivData->psIonClient, psPrivData->psIonHandle);
	}

	psPrivData->bPoisonOnFree = bPoisonOnFree;

	uiPMRFlags = (PMR_FLAGS_T)(uiFlags & PVRSRV_MEMALLOCFLAGS_PMRFLAGSMASK);
	/* check no significant bits were lost in cast due to different
	   bit widths for flags */
	PVR_ASSERT(uiPMRFlags == (uiFlags & PVRSRV_MEMALLOCFLAGS_PMRFLAGSMASK));

	eError = PMRCreatePMR(psPrivData->psPhysHeap,
						  psPrivData->uiSize,
                          psPrivData->uiSize,
                          1,
                          1,
                          &bMappingTable,
						  PAGE_SHIFT,
						  uiPMRFlags,
						  "PMRION",
						  &_sPMRIonFuncTab,
						  psPrivData,
						  &psPMR);
	if (eError != PVRSRV_OK)
	{
		goto fail_pmrcreate;
	}

	_PDumpPMRMalloc(psPMR,
					psPrivData->uiSize,
					PAGE_SIZE,
					&hPDumpAllocInfo);
	psPrivData->hPDumpAllocInfo = hPDumpAllocInfo;
	psPrivData->bPDumpMalloced = IMG_TRUE;

	*ppsPMRPtr = psPMR;
	*puiSize = psPrivData->uiSize;
	*puiAlign = PAGE_SIZE;
	return PVRSRV_OK;

fail_pmrcreate:
fail_kernelmap:
	IonPhysAddrRelease(psPrivData);
fail_acquire:
	ion_free(psPrivData->psIonClient, psPrivData->psIonHandle);
fail_ionimport:
	PhysHeapRelease(psPrivData->psPhysHeap);
fail_physheap:
	kfree(psPrivData);

fail_privalloc:
fail_params:
	PVR_ASSERT(eError != PVRSRV_OK);
	return eError;
}
예제 #13
0
PVRSRV_ERROR IonImportBufferAndAcquirePhysAddr(IMG_HANDLE hIonDev,
											   IMG_UINT32 ui32NumFDs,
											   IMG_INT32  *pai32BufferFDs,
											   IMG_UINT32 *pui32PageCount,
											   IMG_SYS_PHYADDR **ppsSysPhysAddr,
											   IMG_PVOID  *ppvKernAddr0,
											   IMG_HANDLE *phPriv,
											   IMG_HANDLE *phUnique)
{
	struct scatterlist *psTemp, *psScatterList[MAX_IMPORT_ION_FDS] = {};
	PVRSRV_ERROR eError = PVRSRV_ERROR_OUT_OF_MEMORY;
	struct ion_client *psIonClient = hIonDev;
	IMG_UINT32 i, k, ui32PageCount = 0;
	ION_IMPORT_DATA *psImportData;

	if(ui32NumFDs > MAX_IMPORT_ION_FDS)
	{
		printk(KERN_ERR "%s: More ion export fds passed in than supported "
						"(%d provided, %d max)", __func__, ui32NumFDs,
						MAX_IMPORT_ION_FDS);
		return PVRSRV_ERROR_INVALID_PARAMS;
	}

	psImportData = kzalloc(sizeof(ION_IMPORT_DATA), GFP_KERNEL);
	if (psImportData == NULL)
	{
		goto exitFailKMallocImportData;
	}

	/* Set up import data for free call */
	psImportData->psIonClient = psIonClient;
	psImportData->ui32NumIonHandles = ui32NumFDs;

	for(i = 0; i < ui32NumFDs; i++)
	{
		int fd = (int)pai32BufferFDs[i];

		psImportData->apsIonHandle[i] = ion_import_fd(psIonClient, fd);
		if (psImportData->apsIonHandle[i] == IMG_NULL)
		{
			eError = PVRSRV_ERROR_BAD_MAPPING;
			goto exitFailImport;
		}

		psScatterList[i] = ion_map_dma(psIonClient, psImportData->apsIonHandle[i]);
		if (psScatterList[i] == NULL)
		{
			eError = PVRSRV_ERROR_INVALID_PARAMS;
			goto exitFailImport;
		}

		for(psTemp = psScatterList[i]; psTemp; psTemp = sg_next(psTemp))
		{
			IMG_UINT32 j;
			for (j = 0; j < psTemp->length; j += PAGE_SIZE)
			{
				ui32PageCount++;
			}
		}
	}

	BUG_ON(ui32PageCount == 0);

	psImportData->psSysPhysAddr = kmalloc(sizeof(IMG_SYS_PHYADDR) * ui32PageCount, GFP_KERNEL);
	if (psImportData->psSysPhysAddr == NULL)
	{
		goto exitFailImport;
	}

	for(i = 0, k = 0; i < ui32NumFDs; i++)
	{
		for(psTemp = psScatterList[i]; psTemp; psTemp = sg_next(psTemp))
		{
			IMG_UINT32 j;
			for (j = 0; j < psTemp->length; j += PAGE_SIZE)
			{
				psImportData->psSysPhysAddr[k].uiAddr = sg_phys(psTemp) + j;
				k++;
			}
		}
	}

	*pui32PageCount = ui32PageCount;
	*ppsSysPhysAddr = psImportData->psSysPhysAddr;

	if(ui32NumFDs == 1)
	{
		IMG_PVOID pvKernAddr0;

		pvKernAddr0 = ion_map_kernel(psIonClient, psImportData->apsIonHandle[0]);
		if (IS_ERR(pvKernAddr0))
		{
			pvKernAddr0 = IMG_NULL;
		}

		psImportData->pvKernAddr0 = pvKernAddr0;
		*ppvKernAddr0 = pvKernAddr0;
	}
	else
	{
		*ppvKernAddr0 = NULL;
	}

	*phPriv = psImportData;
	*phUnique = (IMG_HANDLE)psImportData->psSysPhysAddr[0].uiAddr;

	return PVRSRV_OK;

exitFailImport:
	for(i = 0; psImportData->apsIonHandle[i] != NULL; i++)
	{
		if(psScatterList[i])
			ion_unmap_dma(psIonClient, psImportData->apsIonHandle[i]);
		ion_free(psIonClient, psImportData->apsIonHandle[i]);
	}
	kfree(psImportData);
exitFailKMallocImportData:
	return eError;
}