コード例 #1
0
ファイル: drm_buffer.c プロジェクト: CSCLOG/beaglebone
/**
 * Copy the user data to the begin of the buffer and reset the processing
 * iterator.
 *
 *   user_data: A pointer the data that is copied to the buffer.
 *   size: The Number of bytes to copy.
 */
int drm_buffer_copy_from_user(struct drm_buffer *buf,
			      void __user *user_data, int size)
{
	int nr_pages = size / PAGE_SIZE + 1;
	int idx;

	if (size > buf->size) {
		DRM_ERROR("Requesting to copy %d bytes to a drm buffer with"
				" %d bytes space\n",
				size, buf->size);
		return -EFAULT;
	}

	for (idx = 0; idx < nr_pages; ++idx) {

		if (DRM_COPY_FROM_USER(buf->data[idx],
			user_data + idx * PAGE_SIZE,
			min(PAGE_SIZE, size - idx * PAGE_SIZE))) {
			DRM_ERROR("Failed to copy user data (%p) to drm buffer"
					" (%p) %dth page.\n",
					user_data, buf, idx);
			return -EFAULT;

		}
	}
	buf->iterator = 0;
	return 0;
}
コード例 #2
0
int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
	struct radeon_device *rdev = dev->dev_private;
	struct drm_radeon_info *info;
	struct radeon_mode_info *minfo = &rdev->mode_info;
	uint32_t *value_ptr;
	uint32_t value;
	struct drm_crtc *crtc;
	int i, found;

	info = data;
	value_ptr = (uint32_t *)((unsigned long)info->value);
	if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
		return -EFAULT;

	switch (info->request) {
	case RADEON_INFO_DEVICE_ID:
		value = dev->pci_device;
		break;
	case RADEON_INFO_NUM_GB_PIPES:
		value = rdev->num_gb_pipes;
		break;
	case RADEON_INFO_NUM_Z_PIPES:
		value = rdev->num_z_pipes;
		break;
	case RADEON_INFO_ACCEL_WORKING:
		/* xf86-video-ati 6.13.0 relies on this being false for evergreen */
		if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK))
			value = false;
		else
			value = rdev->accel_working;
		break;
	case RADEON_INFO_CRTC_FROM_ID:
		for (i = 0, found = 0; i < rdev->num_crtc; i++) {
			crtc = (struct drm_crtc *)minfo->crtcs[i];
			if (crtc && crtc->base.id == value) {
				struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
				value = radeon_crtc->crtc_id;
				found = 1;
				break;
			}
		}
		if (!found) {
			DRM_DEBUG("unknown crtc id %d\n", value);
			return -EINVAL;
		}
		break;
	case RADEON_INFO_ACCEL_WORKING2:
		value = rdev->accel_working;
		break;
	default:
		DRM_DEBUG("Invalid request %d\n", info->request);
		return -EINVAL;
	}
	if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
		DRM_ERROR("copy_to_user\n");
		return -EFAULT;
	}
	return 0;
}
コード例 #3
0
int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx)
{
	int new_page;
	struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
	int i;
	int size = PAGE_SIZE;

	for (i = ibc->last_copied_page + 1; i < pg_idx; i++) {
		if (DRM_COPY_FROM_USER(p->ib->ptr + (i * (PAGE_SIZE/4)),
				       ibc->user_ptr + (i * PAGE_SIZE),
				       PAGE_SIZE)) {
			p->parser_error = -EFAULT;
			return 0;
		}
	}

	new_page = ibc->kpage_idx[0] < ibc->kpage_idx[1] ? 0 : 1;

	if (pg_idx == ibc->last_page_index) {
		size = (ibc->length_dw * 4) % PAGE_SIZE;
			if (size == 0)
				size = PAGE_SIZE;
	}

	if (DRM_COPY_FROM_USER(ibc->kpage[new_page],
			       ibc->user_ptr + (pg_idx * PAGE_SIZE),
			       size)) {
		p->parser_error = -EFAULT;
		return 0;
	}

	/* copy to IB here */
	memcpy((void *)(p->ib->ptr+(pg_idx*(PAGE_SIZE/4))), ibc->kpage[new_page], size);

	ibc->last_copied_page = pg_idx;
	ibc->kpage_idx[new_page] = pg_idx;

	return new_page;
}
コード例 #4
0
int radeon_cs_finish_pages(struct radeon_cs_parser *p)
{
	struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
	int i;
	int size = PAGE_SIZE;

	for (i = ibc->last_copied_page + 1; i <= ibc->last_page_index; i++) {
		if (i == ibc->last_page_index) {
			size = (ibc->length_dw * 4) % PAGE_SIZE;
			if (size == 0)
				size = PAGE_SIZE;
		}
		
		if (DRM_COPY_FROM_USER(p->ib->ptr + (i * (PAGE_SIZE/4)),
				       ibc->user_ptr + (i * PAGE_SIZE),
				       size))
			return -EFAULT;
	}
	return 0;
}
コード例 #5
0
ファイル: qxl_ioctl.c プロジェクト: 03199618/linux
static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
				struct drm_file *file_priv)
{
	struct qxl_device *qdev = dev->dev_private;
	struct drm_qxl_execbuffer *execbuffer = data;
	struct drm_qxl_command user_cmd;
	int cmd_num;
	int ret;

	for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) {

		struct drm_qxl_command *commands =
			(struct drm_qxl_command *)(uintptr_t)execbuffer->commands;

		if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
				       sizeof(user_cmd)))
			return -EFAULT;

		ret = qxl_process_single_command(qdev, &user_cmd, file_priv);
		if (ret)
			return ret;
	}
	return 0;
}
コード例 #6
0
ファイル: radeon_kms.c プロジェクト: aywq2008/omniplay
/*
 * Userspace get information ioctl
 */
int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
    struct radeon_device *rdev = dev->dev_private;
    struct drm_radeon_info *info;
    struct radeon_mode_info *minfo = &rdev->mode_info;
    uint32_t *value_ptr;
    uint32_t value;
    struct drm_crtc *crtc;
    int i, found;

    info = data;
    value_ptr = (uint32_t *)((unsigned long)info->value);
    if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
        return -EFAULT;

    switch (info->request) {
    case RADEON_INFO_DEVICE_ID:
        value = dev->pci_device;
        break;
    case RADEON_INFO_NUM_GB_PIPES:
        value = rdev->num_gb_pipes;
        break;
    case RADEON_INFO_NUM_Z_PIPES:
        value = rdev->num_z_pipes;
        break;
    case RADEON_INFO_ACCEL_WORKING:
        /* xf86-video-ati 6.13.0 relies on this being false for evergreen */
        if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK))
            value = false;
        else
            value = rdev->accel_working;
        break;
    case RADEON_INFO_CRTC_FROM_ID:
        for (i = 0, found = 0; i < rdev->num_crtc; i++) {
            crtc = (struct drm_crtc *)minfo->crtcs[i];
            if (crtc && crtc->base.id == value) {
                struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
                value = radeon_crtc->crtc_id;
                found = 1;
                break;
            }
        }
        if (!found) {
            DRM_DEBUG_KMS("unknown crtc id %d\n", value);
            return -EINVAL;
        }
        break;
    case RADEON_INFO_ACCEL_WORKING2:
        value = rdev->accel_working;
        break;
    case RADEON_INFO_TILING_CONFIG:
        if (rdev->family >= CHIP_TAHITI)
            value = rdev->config.si.tile_config;
        else if (rdev->family >= CHIP_CAYMAN)
            value = rdev->config.cayman.tile_config;
        else if (rdev->family >= CHIP_CEDAR)
            value = rdev->config.evergreen.tile_config;
        else if (rdev->family >= CHIP_RV770)
            value = rdev->config.rv770.tile_config;
        else if (rdev->family >= CHIP_R600)
            value = rdev->config.r600.tile_config;
        else {
            DRM_DEBUG_KMS("tiling config is r6xx+ only!\n");
            return -EINVAL;
        }
        break;
    case RADEON_INFO_WANT_HYPERZ:
        /* The "value" here is both an input and output parameter.
         * If the input value is 1, filp requests hyper-z access.
         * If the input value is 0, filp revokes its hyper-z access.
         *
         * When returning, the value is 1 if filp owns hyper-z access,
         * 0 otherwise. */
        if (value >= 2) {
            DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value);
            return -EINVAL;
        }
        radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, &value);
        break;
    case RADEON_INFO_WANT_CMASK:
        /* The same logic as Hyper-Z. */
        if (value >= 2) {
            DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", value);
            return -EINVAL;
        }
        radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value);
        break;
    case RADEON_INFO_CLOCK_CRYSTAL_FREQ:
        /* return clock value in KHz */
        value = rdev->clock.spll.reference_freq * 10;
        break;
    case RADEON_INFO_NUM_BACKENDS:
        if (rdev->family >= CHIP_TAHITI)
            value = rdev->config.si.max_backends_per_se *
                    rdev->config.si.max_shader_engines;
        else if (rdev->family >= CHIP_CAYMAN)
            value = rdev->config.cayman.max_backends_per_se *
                    rdev->config.cayman.max_shader_engines;
        else if (rdev->family >= CHIP_CEDAR)
            value = rdev->config.evergreen.max_backends;
        else if (rdev->family >= CHIP_RV770)
            value = rdev->config.rv770.max_backends;
        else if (rdev->family >= CHIP_R600)
            value = rdev->config.r600.max_backends;
        else {
            return -EINVAL;
        }
        break;
    case RADEON_INFO_NUM_TILE_PIPES:
        if (rdev->family >= CHIP_TAHITI)
            value = rdev->config.si.max_tile_pipes;
        else if (rdev->family >= CHIP_CAYMAN)
            value = rdev->config.cayman.max_tile_pipes;
        else if (rdev->family >= CHIP_CEDAR)
            value = rdev->config.evergreen.max_tile_pipes;
        else if (rdev->family >= CHIP_RV770)
            value = rdev->config.rv770.max_tile_pipes;
        else if (rdev->family >= CHIP_R600)
            value = rdev->config.r600.max_tile_pipes;
        else {
            return -EINVAL;
        }
        break;
    case RADEON_INFO_FUSION_GART_WORKING:
        value = 1;
        break;
    case RADEON_INFO_BACKEND_MAP:
        if (rdev->family >= CHIP_TAHITI)
            value = rdev->config.si.backend_map;
        else if (rdev->family >= CHIP_CAYMAN)
            value = rdev->config.cayman.backend_map;
        else if (rdev->family >= CHIP_CEDAR)
            value = rdev->config.evergreen.backend_map;
        else if (rdev->family >= CHIP_RV770)
            value = rdev->config.rv770.backend_map;
        else if (rdev->family >= CHIP_R600)
            value = rdev->config.r600.backend_map;
        else {
            return -EINVAL;
        }
        break;
    case RADEON_INFO_VA_START:
        /* this is where we report if vm is supported or not */
        if (rdev->family < CHIP_CAYMAN)
            return -EINVAL;
        value = RADEON_VA_RESERVED_SIZE;
        break;
    case RADEON_INFO_IB_VM_MAX_SIZE:
        /* this is where we report if vm is supported or not */
        if (rdev->family < CHIP_CAYMAN)
            return -EINVAL;
        value = RADEON_IB_VM_MAX_SIZE;
        break;
    case RADEON_INFO_MAX_PIPES:
        if (rdev->family >= CHIP_TAHITI)
            value = rdev->config.si.max_cu_per_sh;
        else if (rdev->family >= CHIP_CAYMAN)
            value = rdev->config.cayman.max_pipes_per_simd;
        else if (rdev->family >= CHIP_CEDAR)
            value = rdev->config.evergreen.max_pipes;
        else if (rdev->family >= CHIP_RV770)
            value = rdev->config.rv770.max_pipes;
        else if (rdev->family >= CHIP_R600)
            value = rdev->config.r600.max_pipes;
        else {
            return -EINVAL;
        }
        break;
    default:
        DRM_DEBUG_KMS("Invalid request %d\n", info->request);
        return -EINVAL;
    }
    if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
        DRM_ERROR("copy_to_user\n");
        return -EFAULT;
    }
    return 0;
}
コード例 #7
0
ファイル: qxl_ioctl.c プロジェクト: 03199618/linux
/*
 * Usage of execbuffer:
 * Relocations need to take into account the full QXLDrawable size.
 * However, the command as passed from user space must *not* contain the initial
 * QXLReleaseInfo struct (first XXX bytes)
 */
static int qxl_process_single_command(struct qxl_device *qdev,
				      struct drm_qxl_command *cmd,
				      struct drm_file *file_priv)
{
	struct qxl_reloc_info *reloc_info;
	int release_type;
	struct qxl_release *release;
	struct qxl_bo *cmd_bo;
	void *fb_cmd;
	int i, j, ret, num_relocs;
	int unwritten;

	switch (cmd->type) {
	case QXL_CMD_DRAW:
		release_type = QXL_RELEASE_DRAWABLE;
		break;
	case QXL_CMD_SURFACE:
	case QXL_CMD_CURSOR:
	default:
		DRM_DEBUG("Only draw commands in execbuffers\n");
		return -EINVAL;
		break;
	}

	if (cmd->command_size > PAGE_SIZE - sizeof(union qxl_release_info))
		return -EINVAL;

	if (!access_ok(VERIFY_READ,
		       (void *)(unsigned long)cmd->command,
		       cmd->command_size))
		return -EFAULT;

	reloc_info = kmalloc(sizeof(struct qxl_reloc_info) * cmd->relocs_num, GFP_KERNEL);
	if (!reloc_info)
		return -ENOMEM;

	ret = qxl_alloc_release_reserved(qdev,
					 sizeof(union qxl_release_info) +
					 cmd->command_size,
					 release_type,
					 &release,
					 &cmd_bo);
	if (ret)
		goto out_free_reloc;

	/* TODO copy slow path code from i915 */
	fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
	unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)cmd->command, cmd->command_size);

	{
		struct qxl_drawable *draw = fb_cmd;
		draw->mm_time = qdev->rom->mm_clock;
	}

	qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
	if (unwritten) {
		DRM_ERROR("got unwritten %d\n", unwritten);
		ret = -EFAULT;
		goto out_free_release;
	}

	/* fill out reloc info structs */
	num_relocs = 0;
	for (i = 0; i < cmd->relocs_num; ++i) {
		struct drm_qxl_reloc reloc;

		if (DRM_COPY_FROM_USER(&reloc,
				       &((struct drm_qxl_reloc *)(uintptr_t)cmd->relocs)[i],
				       sizeof(reloc))) {
			ret = -EFAULT;
			goto out_free_bos;
		}

		/* add the bos to the list of bos to validate -
		   need to validate first then process relocs? */
		if (reloc.reloc_type != QXL_RELOC_TYPE_BO && reloc.reloc_type != QXL_RELOC_TYPE_SURF) {
			DRM_DEBUG("unknown reloc type %d\n", reloc_info[i].type);

			ret = -EINVAL;
			goto out_free_bos;
		}
		reloc_info[i].type = reloc.reloc_type;

		if (reloc.dst_handle) {
			reloc_info[i].dst_bo = qxlhw_handle_to_bo(qdev, file_priv,
								  reloc.dst_handle, release);
			if (!reloc_info[i].dst_bo) {
				ret = -EINVAL;
				reloc_info[i].src_bo = NULL;
				goto out_free_bos;
			}
			reloc_info[i].dst_offset = reloc.dst_offset;
		} else {
			reloc_info[i].dst_bo = cmd_bo;
			reloc_info[i].dst_offset = reloc.dst_offset + release->release_offset;
		}
		num_relocs++;

		/* reserve and validate the reloc dst bo */
		if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) {
			reloc_info[i].src_bo =
				qxlhw_handle_to_bo(qdev, file_priv,
						   reloc.src_handle, release);
			if (!reloc_info[i].src_bo) {
				if (reloc_info[i].dst_bo != cmd_bo)
					drm_gem_object_unreference_unlocked(&reloc_info[i].dst_bo->gem_base);
				ret = -EINVAL;
				goto out_free_bos;
			}
			reloc_info[i].src_offset = reloc.src_offset;
		} else {
			reloc_info[i].src_bo = NULL;
			reloc_info[i].src_offset = 0;
		}
	}

	/* validate all buffers */
	ret = qxl_release_reserve_list(release, false);
	if (ret)
		goto out_free_bos;

	for (i = 0; i < cmd->relocs_num; ++i) {
		if (reloc_info[i].type == QXL_RELOC_TYPE_BO)
			apply_reloc(qdev, &reloc_info[i]);
		else if (reloc_info[i].type == QXL_RELOC_TYPE_SURF)
			apply_surf_reloc(qdev, &reloc_info[i]);
	}

	ret = qxl_push_command_ring_release(qdev, release, cmd->type, true);
	if (ret)
		qxl_release_backoff_reserve_list(release);
	else
		qxl_release_fence_buffer_objects(release);

out_free_bos:
	for (j = 0; j < num_relocs; j++) {
		if (reloc_info[j].dst_bo != cmd_bo)
			drm_gem_object_unreference_unlocked(&reloc_info[j].dst_bo->gem_base);
		if (reloc_info[j].src_bo && reloc_info[j].src_bo != cmd_bo)
			drm_gem_object_unreference_unlocked(&reloc_info[j].src_bo->gem_base);
	}
out_free_release:
	if (ret)
		qxl_release_free(qdev, release);
out_free_reloc:
	kfree(reloc_info);
	return ret;
}
コード例 #8
0
int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
{
	struct drm_radeon_cs *cs = data;
	uint64_t *chunk_array_ptr;
	unsigned size, i;

	if (!cs->num_chunks) {
		return 0;
	}
	/* get chunks */
	INIT_LIST_HEAD(&p->validated);
	p->idx = 0;
	p->chunk_ib_idx = -1;
	p->chunk_relocs_idx = -1;
	p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL);
	if (p->chunks_array == NULL) {
		return -ENOMEM;
	}
	chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks);
	if (DRM_COPY_FROM_USER(p->chunks_array, chunk_array_ptr,
			       sizeof(uint64_t)*cs->num_chunks)) {
		return -EFAULT;
	}
	p->nchunks = cs->num_chunks;
	p->chunks = kcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL);
	if (p->chunks == NULL) {
		return -ENOMEM;
	}
	for (i = 0; i < p->nchunks; i++) {
		struct drm_radeon_cs_chunk __user **chunk_ptr = NULL;
		struct drm_radeon_cs_chunk user_chunk;
		uint32_t __user *cdata;

		chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i];
		if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr,
				       sizeof(struct drm_radeon_cs_chunk))) {
			return -EFAULT;
		}
		p->chunks[i].length_dw = user_chunk.length_dw;
		p->chunks[i].kdata = NULL;
		p->chunks[i].chunk_id = user_chunk.chunk_id;

		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) {
			p->chunk_relocs_idx = i;
		}
		if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) {
			p->chunk_ib_idx = i;
			/* zero length IB isn't useful */
			if (p->chunks[i].length_dw == 0)
				return -EINVAL;
		}

		p->chunks[i].length_dw = user_chunk.length_dw;
		p->chunks[i].user_ptr = (void __user *)(unsigned long)user_chunk.chunk_data;

		cdata = (uint32_t *)(unsigned long)user_chunk.chunk_data;
		if (p->chunks[i].chunk_id != RADEON_CHUNK_ID_IB) {
			size = p->chunks[i].length_dw * sizeof(uint32_t);
			p->chunks[i].kdata = kmalloc(size, GFP_KERNEL);
			if (p->chunks[i].kdata == NULL) {
				return -ENOMEM;
			}
			if (DRM_COPY_FROM_USER(p->chunks[i].kdata,
					       p->chunks[i].user_ptr, size)) {
				return -EFAULT;
			}
		} else {
			p->chunks[i].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL);
			p->chunks[i].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL);
			if (p->chunks[i].kpage[0] == NULL || p->chunks[i].kpage[1] == NULL) {
				kfree(p->chunks[i].kpage[0]);
				kfree(p->chunks[i].kpage[1]);
				return -ENOMEM;
			}
			p->chunks[i].kpage_idx[0] = -1;
			p->chunks[i].kpage_idx[1] = -1;
			p->chunks[i].last_copied_page = -1;
			p->chunks[i].last_page_index = ((p->chunks[i].length_dw * 4) - 1) / PAGE_SIZE;
		}
	}
	if (p->chunks[p->chunk_ib_idx].length_dw > (16 * 1024)) {
		DRM_ERROR("cs IB too big: %d\n",
			  p->chunks[p->chunk_ib_idx].length_dw);
		return -EINVAL;
	}
	return 0;
}
コード例 #9
0
/**
 * radeon_info_ioctl - answer a device specific request.
 *
 * @rdev: radeon device pointer
 * @data: request object
 * @filp: drm filp
 *
 * This function is used to pass device specific parameters to the userspace
 * drivers.  Examples include: pci device id, pipeline parms, tiling params,
 * etc. (all asics).
 * Returns 0 on success, -EINVAL on failure.
 */
int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
    struct radeon_device *rdev = dev->dev_private;
    struct drm_radeon_info *info = data;
    struct radeon_mode_info *minfo = &rdev->mode_info;
    uint32_t *value, value_tmp, *value_ptr, value_size;
    uint64_t value64;
    struct drm_crtc *crtc;
    int i, found;

    value_ptr = (uint32_t *)((unsigned long)info->value);
    value = &value_tmp;
    value_size = sizeof(uint32_t);

    switch (info->request) {
    case RADEON_INFO_DEVICE_ID:
        *value = dev->pdev->device;
        break;
    case RADEON_INFO_NUM_GB_PIPES:
        *value = rdev->num_gb_pipes;
        break;
    case RADEON_INFO_NUM_Z_PIPES:
        *value = rdev->num_z_pipes;
        break;
    case RADEON_INFO_ACCEL_WORKING:
        /* xf86-video-ati 6.13.0 relies on this being false for evergreen */
        if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK))
            *value = false;
        else
            *value = rdev->accel_working;
        break;
    case RADEON_INFO_CRTC_FROM_ID:
        if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
            DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
            return -EFAULT;
        }
        for (i = 0, found = 0; i < rdev->num_crtc; i++) {
            crtc = (struct drm_crtc *)minfo->crtcs[i];
            if (crtc && crtc->base.id == *value) {
                struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
                *value = radeon_crtc->crtc_id;
                found = 1;
                break;
            }
        }
        if (!found) {
            DRM_DEBUG_KMS("unknown crtc id %d\n", *value);
            return -EINVAL;
        }
        break;
    case RADEON_INFO_ACCEL_WORKING2:
        *value = rdev->accel_working;
        break;
    case RADEON_INFO_TILING_CONFIG:
        if (rdev->family >= CHIP_TAHITI)
            *value = rdev->config.si.tile_config;
        else if (rdev->family >= CHIP_CAYMAN)
            *value = rdev->config.cayman.tile_config;
        else if (rdev->family >= CHIP_CEDAR)
            *value = rdev->config.evergreen.tile_config;
        else if (rdev->family >= CHIP_RV770)
            *value = rdev->config.rv770.tile_config;
        else if (rdev->family >= CHIP_R600)
            *value = rdev->config.r600.tile_config;
        else {
            DRM_DEBUG_KMS("tiling config is r6xx+ only!\n");
            return -EINVAL;
        }
        break;
    case RADEON_INFO_WANT_HYPERZ:
        /* The "value" here is both an input and output parameter.
         * If the input value is 1, filp requests hyper-z access.
         * If the input value is 0, filp revokes its hyper-z access.
         *
         * When returning, the value is 1 if filp owns hyper-z access,
         * 0 otherwise. */
        if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
            DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
            return -EFAULT;
        }
        if (*value >= 2) {
            DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", *value);
            return -EINVAL;
        }
        radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, value);
        break;
    case RADEON_INFO_WANT_CMASK:
        /* The same logic as Hyper-Z. */
        if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
            DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
            return -EFAULT;
        }
        if (*value >= 2) {
            DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", *value);
            return -EINVAL;
        }
        radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, value);
        break;
    case RADEON_INFO_CLOCK_CRYSTAL_FREQ:
        /* return clock value in KHz */
        if (rdev->asic->get_xclk)
            *value = radeon_get_xclk(rdev) * 10;
        else
            *value = rdev->clock.spll.reference_freq * 10;
        break;
    case RADEON_INFO_NUM_BACKENDS:
        if (rdev->family >= CHIP_TAHITI)
            *value = rdev->config.si.max_backends_per_se *
                     rdev->config.si.max_shader_engines;
        else if (rdev->family >= CHIP_CAYMAN)
            *value = rdev->config.cayman.max_backends_per_se *
                     rdev->config.cayman.max_shader_engines;
        else if (rdev->family >= CHIP_CEDAR)
            *value = rdev->config.evergreen.max_backends;
        else if (rdev->family >= CHIP_RV770)
            *value = rdev->config.rv770.max_backends;
        else if (rdev->family >= CHIP_R600)
            *value = rdev->config.r600.max_backends;
        else {
            return -EINVAL;
        }
        break;
    case RADEON_INFO_NUM_TILE_PIPES:
        if (rdev->family >= CHIP_TAHITI)
            *value = rdev->config.si.max_tile_pipes;
        else if (rdev->family >= CHIP_CAYMAN)
            *value = rdev->config.cayman.max_tile_pipes;
        else if (rdev->family >= CHIP_CEDAR)
            *value = rdev->config.evergreen.max_tile_pipes;
        else if (rdev->family >= CHIP_RV770)
            *value = rdev->config.rv770.max_tile_pipes;
        else if (rdev->family >= CHIP_R600)
            *value = rdev->config.r600.max_tile_pipes;
        else {
            return -EINVAL;
        }
        break;
    case RADEON_INFO_FUSION_GART_WORKING:
        *value = 1;
        break;
    case RADEON_INFO_BACKEND_MAP:
        if (rdev->family >= CHIP_TAHITI)
            *value = rdev->config.si.backend_map;
        else if (rdev->family >= CHIP_CAYMAN)
            *value = rdev->config.cayman.backend_map;
        else if (rdev->family >= CHIP_CEDAR)
            *value = rdev->config.evergreen.backend_map;
        else if (rdev->family >= CHIP_RV770)
            *value = rdev->config.rv770.backend_map;
        else if (rdev->family >= CHIP_R600)
            *value = rdev->config.r600.backend_map;
        else {
            return -EINVAL;
        }
        break;
    case RADEON_INFO_VA_START:
        /* this is where we report if vm is supported or not */
        if (rdev->family < CHIP_CAYMAN)
            return -EINVAL;
        *value = RADEON_VA_RESERVED_SIZE;
        break;
    case RADEON_INFO_IB_VM_MAX_SIZE:
        /* this is where we report if vm is supported or not */
        if (rdev->family < CHIP_CAYMAN)
            return -EINVAL;
        *value = RADEON_IB_VM_MAX_SIZE;
        break;
    case RADEON_INFO_MAX_PIPES:
        if (rdev->family >= CHIP_TAHITI)
            *value = rdev->config.si.max_cu_per_sh;
        else if (rdev->family >= CHIP_CAYMAN)
            *value = rdev->config.cayman.max_pipes_per_simd;
        else if (rdev->family >= CHIP_CEDAR)
            *value = rdev->config.evergreen.max_pipes;
        else if (rdev->family >= CHIP_RV770)
            *value = rdev->config.rv770.max_pipes;
        else if (rdev->family >= CHIP_R600)
            *value = rdev->config.r600.max_pipes;
        else {
            return -EINVAL;
        }
        break;
    case RADEON_INFO_TIMESTAMP:
        if (rdev->family < CHIP_R600) {
            DRM_DEBUG_KMS("timestamp is r6xx+ only!\n");
            return -EINVAL;
        }
        value = (uint32_t*)&value64;
        value_size = sizeof(uint64_t);
        value64 = radeon_get_gpu_clock_counter(rdev);
        break;
    case RADEON_INFO_MAX_SE:
        if (rdev->family >= CHIP_TAHITI)
            *value = rdev->config.si.max_shader_engines;
        else if (rdev->family >= CHIP_CAYMAN)
            *value = rdev->config.cayman.max_shader_engines;
        else if (rdev->family >= CHIP_CEDAR)
            *value = rdev->config.evergreen.num_ses;
        else
            *value = 1;
        break;
    case RADEON_INFO_MAX_SH_PER_SE:
        if (rdev->family >= CHIP_TAHITI)
            *value = rdev->config.si.max_sh_per_se;
        else
            return -EINVAL;
        break;
    case RADEON_INFO_FASTFB_WORKING:
        *value = rdev->fastfb_working;
        break;
    case RADEON_INFO_RING_WORKING:
        if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
            DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
            return -EFAULT;
        }
        switch (*value) {
        case RADEON_CS_RING_GFX:
        case RADEON_CS_RING_COMPUTE:
            *value = rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready;
            break;
        case RADEON_CS_RING_DMA:
            *value = rdev->ring[R600_RING_TYPE_DMA_INDEX].ready;
            *value |= rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready;
            break;
        case RADEON_CS_RING_UVD:
            *value = rdev->ring[R600_RING_TYPE_UVD_INDEX].ready;
            break;
        default:
            return -EINVAL;
        }
        break;
    case RADEON_INFO_SI_TILE_MODE_ARRAY:
        if (rdev->family < CHIP_TAHITI) {
            DRM_DEBUG_KMS("tile mode array is si only!\n");
            return -EINVAL;
        }
        value = rdev->config.si.tile_mode_array;
        value_size = sizeof(uint32_t)*32;
        break;
    case RADEON_INFO_SI_CP_DMA_COMPUTE:
        *value = 1;
        break;
    default:
        DRM_DEBUG_KMS("Invalid request %d\n", info->request);
        return -EINVAL;
    }
    if (DRM_COPY_TO_USER(value_ptr, (char*)value, value_size)) {
        DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
        return -EFAULT;
    }
    return 0;
}
コード例 #10
0
/*
 * Userspace get information ioctl
 */
int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
	struct radeon_device *rdev = dev->dev_private;
	struct drm_radeon_info *info;
	struct radeon_mode_info *minfo = &rdev->mode_info;
	uint32_t *value_ptr;
	uint32_t value;
	struct drm_crtc *crtc;
	int i, found;

	info = data;
	value_ptr = (uint32_t *)((unsigned long)info->value);
	if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
		return -EFAULT;

	switch (info->request) {
	case RADEON_INFO_DEVICE_ID:
		value = dev->pci_device;
		break;
	case RADEON_INFO_NUM_GB_PIPES:
		value = rdev->num_gb_pipes;
		break;
	case RADEON_INFO_NUM_Z_PIPES:
		value = rdev->num_z_pipes;
		break;
	case RADEON_INFO_ACCEL_WORKING:
		/* xf86-video-ati 6.13.0 relies on this being false for evergreen */
		if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK))
			value = false;
		else
			value = rdev->accel_working;
		break;
	case RADEON_INFO_CRTC_FROM_ID:
		for (i = 0, found = 0; i < rdev->num_crtc; i++) {
			crtc = (struct drm_crtc *)minfo->crtcs[i];
			if (crtc && crtc->base.id == value) {
				struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
				value = radeon_crtc->crtc_id;
				found = 1;
				break;
			}
		}
		if (!found) {
			DRM_DEBUG_KMS("unknown crtc id %d\n", value);
			return -EINVAL;
		}
		break;
	case RADEON_INFO_ACCEL_WORKING2:
		value = rdev->accel_working;
		break;
	case RADEON_INFO_TILING_CONFIG:
		if (rdev->family >= CHIP_CEDAR)
			value = rdev->config.evergreen.tile_config;
		else if (rdev->family >= CHIP_RV770)
			value = rdev->config.rv770.tile_config;
		else if (rdev->family >= CHIP_R600)
			value = rdev->config.r600.tile_config;
		else {
			DRM_DEBUG_KMS("tiling config is r6xx+ only!\n");
			return -EINVAL;
		}
		break;
	case RADEON_INFO_WANT_HYPERZ:
		/* The "value" here is both an input and output parameter.
		 * If the input value is 1, filp requests hyper-z access.
		 * If the input value is 0, filp revokes its hyper-z access.
		 *
		 * When returning, the value is 1 if filp owns hyper-z access,
		 * 0 otherwise. */
		if (value >= 2) {
			DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value);
			return -EINVAL;
		}
		radeon_set_filp_rights(dev, &rdev->hyperz_filp, filp, &value);
		break;
	case RADEON_INFO_WANT_CMASK:
		/* The same logic as Hyper-Z. */
		if (value >= 2) {
			DRM_DEBUG_KMS("WANT_CMASK: invalid value %d\n", value);
			return -EINVAL;
		}
		radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value);
		break;
	default:
		DRM_DEBUG_KMS("Invalid request %d\n", info->request);
		return -EINVAL;
	}
	if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
		DRM_ERROR("copy_to_user\n");
		return -EFAULT;
	}
	return 0;
}
コード例 #11
0
ファイル: qxl_ioctl.c プロジェクト: glpaschall/linux
/*
 * Usage of execbuffer:
 * Relocations need to take into account the full QXLDrawable size.
 * However, the command as passed from user space must *not* contain the initial
 * QXLReleaseInfo struct (first XXX bytes)
 */
static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
				struct drm_file *file_priv)
{
	struct qxl_device *qdev = dev->dev_private;
	struct drm_qxl_execbuffer *execbuffer = data;
	struct drm_qxl_command user_cmd;
	int cmd_num;
	struct qxl_bo *reloc_src_bo;
	struct qxl_bo *reloc_dst_bo;
	struct drm_qxl_reloc reloc;
	void *fb_cmd;
	int i, ret;
	struct qxl_reloc_list reloc_list;
	int unwritten;
	uint32_t reloc_dst_offset;
	INIT_LIST_HEAD(&reloc_list.bos);

	for (cmd_num = 0; cmd_num < execbuffer->commands_num; ++cmd_num) {
		struct qxl_release *release;
		struct qxl_bo *cmd_bo;
		int release_type;
		struct drm_qxl_command *commands =
			(struct drm_qxl_command *)execbuffer->commands;

		if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
				       sizeof(user_cmd)))
			return -EFAULT;
		switch (user_cmd.type) {
		case QXL_CMD_DRAW:
			release_type = QXL_RELEASE_DRAWABLE;
			break;
		case QXL_CMD_SURFACE:
		case QXL_CMD_CURSOR:
		default:
			DRM_DEBUG("Only draw commands in execbuffers\n");
			return -EINVAL;
			break;
		}

		if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info))
			return -EINVAL;

		ret = qxl_alloc_release_reserved(qdev,
						 sizeof(union qxl_release_info) +
						 user_cmd.command_size,
						 release_type,
						 &release,
						 &cmd_bo);
		if (ret)
			return ret;

		/* TODO copy slow path code from i915 */
		fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
		unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size);
		qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
		if (unwritten) {
			DRM_ERROR("got unwritten %d\n", unwritten);
			qxl_release_unreserve(qdev, release);
			qxl_release_free(qdev, release);
			return -EFAULT;
		}

		for (i = 0 ; i < user_cmd.relocs_num; ++i) {
			if (DRM_COPY_FROM_USER(&reloc,
					       &((struct drm_qxl_reloc *)user_cmd.relocs)[i],
					       sizeof(reloc))) {
				qxl_bo_list_unreserve(&reloc_list, true);
				qxl_release_unreserve(qdev, release);
				qxl_release_free(qdev, release);
				return -EFAULT;
			}

			/* add the bos to the list of bos to validate -
			   need to validate first then process relocs? */
			if (reloc.dst_handle) {
				reloc_dst_bo = qxlhw_handle_to_bo(qdev, file_priv,
								  reloc.dst_handle, &reloc_list);
				if (!reloc_dst_bo) {
					qxl_bo_list_unreserve(&reloc_list, true);
					qxl_release_unreserve(qdev, release);
					qxl_release_free(qdev, release);
					return -EINVAL;
				}
				reloc_dst_offset = 0;
			} else {
				reloc_dst_bo = cmd_bo;
				reloc_dst_offset = release->release_offset;
			}

			/* reserve and validate the reloc dst bo */
			if (reloc.reloc_type == QXL_RELOC_TYPE_BO || reloc.src_handle > 0) {
				reloc_src_bo =
					qxlhw_handle_to_bo(qdev, file_priv,
							   reloc.src_handle, &reloc_list);
				if (!reloc_src_bo) {
					if (reloc_dst_bo != cmd_bo)
						drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base);
					qxl_bo_list_unreserve(&reloc_list, true);
					qxl_release_unreserve(qdev, release);
					qxl_release_free(qdev, release);
					return -EINVAL;
				}
			} else
				reloc_src_bo = NULL;
			if (reloc.reloc_type == QXL_RELOC_TYPE_BO) {
				apply_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset,
					    reloc_src_bo, reloc.src_offset);
			} else if (reloc.reloc_type == QXL_RELOC_TYPE_SURF) {
				apply_surf_reloc(qdev, reloc_dst_bo, reloc_dst_offset + reloc.dst_offset, reloc_src_bo);
			} else {
				DRM_ERROR("unknown reloc type %d\n", reloc.reloc_type);
				return -EINVAL;
			}

			if (reloc_src_bo && reloc_src_bo != cmd_bo) {
				qxl_release_add_res(qdev, release, reloc_src_bo);
				drm_gem_object_unreference_unlocked(&reloc_src_bo->gem_base);
			}

			if (reloc_dst_bo != cmd_bo)
				drm_gem_object_unreference_unlocked(&reloc_dst_bo->gem_base);
		}
		qxl_fence_releaseable(qdev, release);

		ret = qxl_push_command_ring_release(qdev, release, user_cmd.type, true);
		if (ret == -ERESTARTSYS) {
			qxl_release_unreserve(qdev, release);
			qxl_release_free(qdev, release);
			qxl_bo_list_unreserve(&reloc_list, true);
			return ret;
		}
		qxl_release_unreserve(qdev, release);
	}
	qxl_bo_list_unreserve(&reloc_list, 0);
	return 0;
}
コード例 #12
0
ファイル: drm_drawable.c プロジェクト: 274914765/C
int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
    struct drm_update_draw *update = data;
    unsigned long irqflags;
    struct drm_clip_rect *rects;
    struct drm_drawable_info *info;
    int err;

    info = idr_find(&dev->drw_idr, update->handle);
    if (!info) {
        info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS);
        if (!info)
            return -ENOMEM;
        if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
            DRM_ERROR("No such drawable %d\n", update->handle);
            drm_free(info, sizeof(*info), DRM_MEM_BUFS);
            return -EINVAL;
        }
    }

    switch (update->type) {
    case DRM_DRAWABLE_CLIPRECTS:
        if (update->num != info->num_rects) {
            rects = drm_alloc(update->num * sizeof(struct drm_clip_rect),
                     DRM_MEM_BUFS);
        } else
            rects = info->rects;

        if (update->num && !rects) {
            DRM_ERROR("Failed to allocate cliprect memory\n");
            err = -ENOMEM;
            goto error;
        }

        if (update->num && DRM_COPY_FROM_USER(rects,
                             (struct drm_clip_rect __user *)
                             (unsigned long)update->data,
                             update->num *
                             sizeof(*rects))) {
            DRM_ERROR("Failed to copy cliprects from userspace\n");
            err = -EFAULT;
            goto error;
        }

        spin_lock_irqsave(&dev->drw_lock, irqflags);

        if (rects != info->rects) {
            drm_free(info->rects, info->num_rects *
                 sizeof(struct drm_clip_rect), DRM_MEM_BUFS);
        }

        info->rects = rects;
        info->num_rects = update->num;

        spin_unlock_irqrestore(&dev->drw_lock, irqflags);

        DRM_DEBUG("Updated %d cliprects for drawable %d\n",
              info->num_rects, update->handle);
        break;
    default:
        DRM_ERROR("Invalid update type %d\n", update->type);
        return -EINVAL;
    }

    return 0;

error:
    if (rects != info->rects)
        drm_free(rects, update->num * sizeof(struct drm_clip_rect),
             DRM_MEM_BUFS);

    return err;
}