/** * DOC: PowerVR (Series 6 and later) and IMG Graphics Driver * * This driver supports the following PowerVR/IMG graphics cores from Imagination Technologies: * * * AXE-1-16M (found in Texas Instruments AM62) * * BXS-4-64 MC1 (found in Texas Instruments J721S2/AM68)
*/
/** * pvr_ioctl_create_bo() - IOCTL to create a GEM buffer object. * @drm_dev: [IN] Target DRM device. * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_create_bo_args. * @file: [IN] DRM file-private data. * * Called from userspace with %DRM_IOCTL_PVR_CREATE_BO. * * Return: * * 0 on success, * * -%EINVAL if the value of &drm_pvr_ioctl_create_bo_args.size is zero * or wider than &typedef size_t, * * -%EINVAL if any bits in &drm_pvr_ioctl_create_bo_args.flags that are * reserved or undefined are set, * * -%EINVAL if any padding fields in &drm_pvr_ioctl_create_bo_args are not * zero, * * Any error encountered while creating the object (see * pvr_gem_object_create()), or * * Any error encountered while transferring ownership of the object into a * userspace-accessible handle (see pvr_gem_object_into_handle()).
*/ staticint
pvr_ioctl_create_bo(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_create_bo_args *args = raw_args; struct pvr_device *pvr_dev = to_pvr_device(drm_dev); struct pvr_file *pvr_file = to_pvr_file(file);
/* All padding fields must be zeroed. */ if (args->_padding_c != 0) {
err = -EINVAL; goto err_drm_dev_exit;
}
/* * On 64-bit platforms (our primary target), size_t is a u64. However, * on other architectures we have to check for overflow when casting * down to size_t from u64. * * We also disallow zero-sized allocations, and reserved (kernel-only) * flags.
*/ if (args->size > SIZE_MAX || args->size == 0 || args->flags &
~DRM_PVR_BO_FLAGS_MASK || args->size & (PVR_DEVICE_PAGE_SIZE - 1)) {
err = -EINVAL; goto err_drm_dev_exit;
}
sanitized_size = (size_t)args->size;
/* * Create a buffer object and transfer ownership to a userspace- * accessible handle.
*/
pvr_obj = pvr_gem_object_create(pvr_dev, sanitized_size, args->flags); if (IS_ERR(pvr_obj)) {
err = PTR_ERR(pvr_obj); goto err_drm_dev_exit;
}
/* This function will not modify &args->handle unless it succeeds. */
err = pvr_gem_object_into_handle(pvr_obj, pvr_file, &args->handle); if (err) goto err_destroy_obj;
drm_dev_exit(idx);
return 0;
err_destroy_obj: /* * GEM objects are refcounted, so there is no explicit destructor * function. Instead, we release the singular reference we currently * hold on the object and let GEM take care of the rest.
*/
pvr_gem_object_put(pvr_obj);
err_drm_dev_exit:
drm_dev_exit(idx);
return err;
}
/** * pvr_ioctl_get_bo_mmap_offset() - IOCTL to generate a "fake" offset to be * used when calling mmap() from userspace to map the given GEM buffer object * @drm_dev: [IN] DRM device (unused). * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_get_bo_mmap_offset_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_GET_BO_MMAP_OFFSET. * * This IOCTL does *not* perform an mmap. See the docs on * &struct drm_pvr_ioctl_get_bo_mmap_offset_args for details. * * Return: * * 0 on success, * * -%ENOENT if the handle does not reference a valid GEM buffer object, * * -%EINVAL if any padding fields in &struct * drm_pvr_ioctl_get_bo_mmap_offset_args are not zero, or * * Any error returned by drm_gem_create_mmap_offset().
*/ staticint
pvr_ioctl_get_bo_mmap_offset(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_get_bo_mmap_offset_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_gem_object *pvr_obj; struct drm_gem_object *gem_obj; int idx; int ret;
if (!drm_dev_enter(drm_dev, &idx)) return -EIO;
/* All padding fields must be zeroed. */ if (args->_padding_4 != 0) {
ret = -EINVAL; goto err_drm_dev_exit;
}
/* * Obtain a kernel reference to the buffer object. This reference is * counted and must be manually dropped before returning. If a buffer * object cannot be found for the specified handle, return -%ENOENT (No * such file or directory).
*/
pvr_obj = pvr_gem_object_from_handle(pvr_file, args->handle); if (!pvr_obj) {
ret = -ENOENT; goto err_drm_dev_exit;
}
gem_obj = gem_from_pvr_gem(pvr_obj);
/* * Allocate a fake offset which can be used in userspace calls to mmap * on the DRM device file. If this fails, return the error code. This * operation is idempotent.
*/
ret = drm_gem_create_mmap_offset(gem_obj); if (ret != 0) { /* Drop our reference to the buffer object. */
drm_gem_object_put(gem_obj); goto err_drm_dev_exit;
}
/* * Read out the fake offset allocated by the earlier call to * drm_gem_create_mmap_offset.
*/
args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
/* Drop our reference to the buffer object. */
pvr_gem_object_put(pvr_obj);
/* * Compute tasks on cores with BRN48492 and without compute overlap may lock * up without two additional lines of coeffs.
*/ if (PVR_HAS_QUIRK(pvr_dev, 48492) && !PVR_HAS_FEATURE(pvr_dev, compute_overlap))
pending_allocation_coeff_regs = 2U * 1024U;
if (PVR_HAS_ENHANCEMENT(pvr_dev, 38748))
pending_allocation_shared_regs = 0;
if (PVR_HAS_ENHANCEMENT(pvr_dev, 38020))
max_coeff_additional_portion += ROGUE_MAX_COMPUTE_SHARED_REGISTERS;
if (PVR_HAS_QUIRK(pvr_dev, 48492) && PVR_HAS_FEATURE(pvr_dev, roguexe) &&
!PVR_HAS_FEATURE(pvr_dev, compute_overlap)) { /* Driver must not use the 2 reserved lines. */
available_coeffs_in_dwords -= ROGUE_CSRM_LINE_SIZE_IN_DWORDS * 2;
}
/* * The maximum amount of local memory available to a kernel is the minimum * of the total number of coefficient registers available and the max common * store allocation size which can be made by the CDM. * * If any coeff lines are reserved for tessellation or pixel then we need to * subtract those too.
*/ return min(available_coeffs_in_dwords, (u32)ROGUE_MAX_PER_KERNEL_LOCAL_MEM_SIZE_REGS);
}
/** * pvr_dev_query_gpu_info_get() * @pvr_dev: Device pointer. * @args: [IN] Device query arguments containing a pointer to a userspace * struct drm_pvr_dev_query_gpu_info. * * If the query object pointer is NULL, the size field is updated with the * expected size of the query object. * * Returns: * * 0 on success, or if size is requested using a NULL pointer, or * * -%E2BIG if the indicated length of the allocation is less than is * required to contain the copied data, or * * -%EFAULT if local memory could not be copied to userspace.
*/ staticint
pvr_dev_query_gpu_info_get(struct pvr_device *pvr_dev, struct drm_pvr_ioctl_dev_query_args *args)
{ struct drm_pvr_dev_query_gpu_info gpu_info = {0}; int err;
if (!args->pointer) {
args->size = sizeof(struct drm_pvr_dev_query_gpu_info); return 0;
}
if (args->size > sizeof(gpu_info))
args->size = sizeof(gpu_info); return 0;
}
/** * pvr_dev_query_runtime_info_get() * @pvr_dev: Device pointer. * @args: [IN] Device query arguments containing a pointer to a userspace * struct drm_pvr_dev_query_runtime_info. * * If the query object pointer is NULL, the size field is updated with the * expected size of the query object. * * Returns: * * 0 on success, or if size is requested using a NULL pointer, or * * -%E2BIG if the indicated length of the allocation is less than is * required to contain the copied data, or * * -%EFAULT if local memory could not be copied to userspace.
*/ staticint
pvr_dev_query_runtime_info_get(struct pvr_device *pvr_dev, struct drm_pvr_ioctl_dev_query_args *args)
{ struct drm_pvr_dev_query_runtime_info runtime_info = {0}; int err;
if (!args->pointer) {
args->size = sizeof(struct drm_pvr_dev_query_runtime_info); return 0;
}
if (args->size > sizeof(runtime_info))
args->size = sizeof(runtime_info); return 0;
}
/** * pvr_dev_query_quirks_get() - Unpack array of quirks at the address given * in a struct drm_pvr_dev_query_quirks, or gets the amount of space required * for it. * @pvr_dev: Device pointer. * @args: [IN] Device query arguments containing a pointer to a userspace * struct drm_pvr_dev_query_query_quirks. * * If the query object pointer is NULL, the size field is updated with the * expected size of the query object. * If the userspace pointer in the query object is NULL, or the count is * short, no data is copied. * The count field will be updated to that copied, or if either pointer is * NULL, that which would have been copied. * The size field in the query object will be updated to the size copied. * * Returns: * * 0 on success, or if size/count is requested using a NULL pointer, or * * -%EINVAL if args contained non-zero reserved fields, or * * -%E2BIG if the indicated length of the allocation is less than is * required to contain the copied data, or * * -%EFAULT if local memory could not be copied to userspace.
*/ staticint
pvr_dev_query_quirks_get(struct pvr_device *pvr_dev, struct drm_pvr_ioctl_dev_query_args *args)
{ /* * @FIXME - hardcoding of numbers here is intended as an * intermediate step so the UAPI can be fixed, but requires a * a refactor in the future to store them in a more appropriate * location
*/ staticconst u32 umd_quirks_musthave[] = {
47217,
49927,
62269,
}; staticconst u32 umd_quirks[] = {
48545,
51764,
}; struct drm_pvr_dev_query_quirks query;
u32 out[ARRAY_SIZE(umd_quirks_musthave) + ARRAY_SIZE(umd_quirks)];
size_t out_musthave_count = 0;
size_t out_count = 0; int err;
if (!args->pointer) {
args->size = sizeof(struct drm_pvr_dev_query_quirks); return 0;
}
if (err < 0) return err; if (query._padding_c) return -EINVAL;
for (int i = 0; i < ARRAY_SIZE(umd_quirks_musthave); i++) { if (pvr_device_has_uapi_quirk(pvr_dev, umd_quirks_musthave[i])) {
out[out_count++] = umd_quirks_musthave[i];
out_musthave_count++;
}
}
for (int i = 0; i < ARRAY_SIZE(umd_quirks); i++) { if (pvr_device_has_uapi_quirk(pvr_dev, umd_quirks[i]))
out[out_count++] = umd_quirks[i];
}
if (!query.quirks) goto copy_out; if (query.count < out_count) return -E2BIG;
if (copy_to_user(u64_to_user_ptr(query.quirks), out,
out_count * sizeof(u32))) { return -EFAULT;
}
/** * pvr_dev_query_enhancements_get() - Unpack array of enhancements at the * address given in a struct drm_pvr_dev_query_enhancements, or gets the amount * of space required for it. * @pvr_dev: Device pointer. * @args: [IN] Device query arguments containing a pointer to a userspace * struct drm_pvr_dev_query_enhancements. * * If the query object pointer is NULL, the size field is updated with the * expected size of the query object. * If the userspace pointer in the query object is NULL, or the count is * short, no data is copied. * The count field will be updated to that copied, or if either pointer is * NULL, that which would have been copied. * The size field in the query object will be updated to the size copied. * * Returns: * * 0 on success, or if size/count is requested using a NULL pointer, or * * -%EINVAL if args contained non-zero reserved fields, or * * -%E2BIG if the indicated length of the allocation is less than is * required to contain the copied data, or * * -%EFAULT if local memory could not be copied to userspace.
*/ staticint
pvr_dev_query_enhancements_get(struct pvr_device *pvr_dev, struct drm_pvr_ioctl_dev_query_args *args)
{ /* * @FIXME - hardcoding of numbers here is intended as an * intermediate step so the UAPI can be fixed, but requires a * a refactor in the future to store them in a more appropriate * location
*/ const u32 umd_enhancements[] = {
35421,
42064,
}; struct drm_pvr_dev_query_enhancements query;
u32 out[ARRAY_SIZE(umd_enhancements)];
size_t out_idx = 0; int err;
if (!args->pointer) {
args->size = sizeof(struct drm_pvr_dev_query_enhancements); return 0;
}
if (err < 0) return err; if (query._padding_a) return -EINVAL; if (query._padding_c) return -EINVAL;
for (int i = 0; i < ARRAY_SIZE(umd_enhancements); i++) { if (pvr_device_has_uapi_enhancement(pvr_dev, umd_enhancements[i]))
out[out_idx++] = umd_enhancements[i];
}
if (!query.enhancements) goto copy_out; if (query.count < out_idx) return -E2BIG;
if (copy_to_user(u64_to_user_ptr(query.enhancements), out,
out_idx * sizeof(u32))) { return -EFAULT;
}
/** * pvr_ioctl_dev_query() - IOCTL to copy information about a device * @drm_dev: [IN] DRM device. * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_dev_query_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_DEV_QUERY. * If the given receiving struct pointer is NULL, or the indicated size is too * small, the expected size of the struct type will be returned in the size * argument field. * * Return: * * 0 on success or when fetching the size with args->pointer == NULL, or * * -%E2BIG if the indicated size of the receiving struct is less than is * required to contain the copied data, or * * -%EINVAL if the indicated struct type is unknown, or * * -%ENOMEM if local memory could not be allocated, or * * -%EFAULT if local memory could not be copied to userspace.
*/ staticint
pvr_ioctl_dev_query(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct pvr_device *pvr_dev = to_pvr_device(drm_dev); struct drm_pvr_ioctl_dev_query_args *args = raw_args; int idx; int ret = -EINVAL;
if (!drm_dev_enter(drm_dev, &idx)) return -EIO;
switch ((enum drm_pvr_dev_query)args->type) { case DRM_PVR_DEV_QUERY_GPU_INFO_GET:
ret = pvr_dev_query_gpu_info_get(pvr_dev, args); break;
case DRM_PVR_DEV_QUERY_RUNTIME_INFO_GET:
ret = pvr_dev_query_runtime_info_get(pvr_dev, args); break;
case DRM_PVR_DEV_QUERY_QUIRKS_GET:
ret = pvr_dev_query_quirks_get(pvr_dev, args); break;
case DRM_PVR_DEV_QUERY_ENHANCEMENTS_GET:
ret = pvr_dev_query_enhancements_get(pvr_dev, args); break;
case DRM_PVR_DEV_QUERY_HEAP_INFO_GET:
ret = pvr_heap_info_get(pvr_dev, args); break;
case DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET:
ret = pvr_static_data_areas_get(pvr_dev, args); break;
}
drm_dev_exit(idx);
return ret;
}
/** * pvr_ioctl_create_context() - IOCTL to create a context * @drm_dev: [IN] DRM device. * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_create_context_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_CREATE_CONTEXT. * * Return: * * 0 on success, or * * -%EINVAL if provided arguments are invalid, or * * -%EFAULT if arguments can't be copied from userspace, or * * Any error returned by pvr_create_render_context().
*/ staticint
pvr_ioctl_create_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_create_context_args *args = raw_args; struct pvr_file *pvr_file = file->driver_priv; int idx; int ret;
if (!drm_dev_enter(drm_dev, &idx)) return -EIO;
ret = pvr_context_create(pvr_file, args);
drm_dev_exit(idx);
return ret;
}
/** * pvr_ioctl_destroy_context() - IOCTL to destroy a context * @drm_dev: [IN] DRM device. * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_destroy_context_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_DESTROY_CONTEXT. * * Return: * * 0 on success, or * * -%EINVAL if context not in context list.
*/ staticint
pvr_ioctl_destroy_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_destroy_context_args *args = raw_args; struct pvr_file *pvr_file = file->driver_priv;
/** * pvr_ioctl_create_free_list() - IOCTL to create a free list * @drm_dev: [IN] DRM device. * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_create_free_list_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_CREATE_FREE_LIST. * * Return: * * 0 on success, or * * Any error returned by pvr_free_list_create().
*/ staticint
pvr_ioctl_create_free_list(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_create_free_list_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_free_list *free_list; int idx; int err;
/* Allocate object handle for userspace. */
err = xa_alloc(&pvr_file->free_list_handles,
&args->handle,
free_list,
xa_limit_32b,
GFP_KERNEL); if (err < 0) goto err_cleanup;
drm_dev_exit(idx);
return 0;
err_cleanup:
pvr_free_list_put(free_list);
err_drm_dev_exit:
drm_dev_exit(idx);
return err;
}
/** * pvr_ioctl_destroy_free_list() - IOCTL to destroy a free list * @drm_dev: [IN] DRM device. * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_destroy_free_list_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_DESTROY_FREE_LIST. * * Return: * * 0 on success, or * * -%EINVAL if free list not in object list.
*/ staticint
pvr_ioctl_destroy_free_list(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_destroy_free_list_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_free_list *free_list;
if (args->_padding_4) return -EINVAL;
free_list = xa_erase(&pvr_file->free_list_handles, args->handle); if (!free_list) return -EINVAL;
pvr_free_list_put(free_list); return 0;
}
/** * pvr_ioctl_create_hwrt_dataset() - IOCTL to create a HWRT dataset * @drm_dev: [IN] DRM device. * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_create_hwrt_dataset_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_CREATE_HWRT_DATASET. * * Return: * * 0 on success, or * * Any error returned by pvr_hwrt_dataset_create().
*/ staticint
pvr_ioctl_create_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_create_hwrt_dataset_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_hwrt_dataset *hwrt; int idx; int err;
/* Allocate object handle for userspace. */
err = xa_alloc(&pvr_file->hwrt_handles,
&args->handle,
hwrt,
xa_limit_32b,
GFP_KERNEL); if (err < 0) goto err_cleanup;
drm_dev_exit(idx);
return 0;
err_cleanup:
pvr_hwrt_dataset_put(hwrt);
err_drm_dev_exit:
drm_dev_exit(idx);
return err;
}
/** * pvr_ioctl_destroy_hwrt_dataset() - IOCTL to destroy a HWRT dataset * @drm_dev: [IN] DRM device. * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_destroy_hwrt_dataset_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_DESTROY_HWRT_DATASET. * * Return: * * 0 on success, or * * -%EINVAL if HWRT dataset not in object list.
*/ staticint
pvr_ioctl_destroy_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_destroy_hwrt_dataset_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_hwrt_dataset *hwrt;
if (args->_padding_4) return -EINVAL;
hwrt = xa_erase(&pvr_file->hwrt_handles, args->handle); if (!hwrt) return -EINVAL;
pvr_hwrt_dataset_put(hwrt); return 0;
}
/** * pvr_ioctl_create_vm_context() - IOCTL to create a VM context * @drm_dev: [IN] DRM device. * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_create_vm_context_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_CREATE_VM_CONTEXT. * * Return: * * 0 on success, or * * Any error returned by pvr_vm_create_context().
*/ staticint
pvr_ioctl_create_vm_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_create_vm_context_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_vm_context *vm_ctx; int idx; int err;
if (!drm_dev_enter(drm_dev, &idx)) return -EIO;
if (args->_padding_4) {
err = -EINVAL; goto err_drm_dev_exit;
}
/* Allocate object handle for userspace. */
err = xa_alloc(&pvr_file->vm_ctx_handles,
&args->handle,
vm_ctx,
xa_limit_32b,
GFP_KERNEL); if (err < 0) goto err_cleanup;
drm_dev_exit(idx);
return 0;
err_cleanup:
pvr_vm_context_put(vm_ctx);
err_drm_dev_exit:
drm_dev_exit(idx);
return err;
}
/** * pvr_ioctl_destroy_vm_context() - IOCTL to destroy a VM context * @drm_dev: [IN] DRM device. * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_destroy_vm_context_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_DESTROY_VM_CONTEXT. * * Return: * * 0 on success, or * * -%EINVAL if object not in object list.
*/ staticint
pvr_ioctl_destroy_vm_context(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_destroy_vm_context_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_vm_context *vm_ctx;
if (args->_padding_4) return -EINVAL;
vm_ctx = xa_erase(&pvr_file->vm_ctx_handles, args->handle); if (!vm_ctx) return -EINVAL;
pvr_vm_context_put(vm_ctx); return 0;
}
/** * pvr_ioctl_vm_map() - IOCTL to map buffer to GPU address space. * @drm_dev: [IN] DRM device. * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_vm_map_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_VM_MAP. * * Return: * * 0 on success, * * -%EINVAL if &drm_pvr_ioctl_vm_op_map_args.flags is not zero, * * -%EINVAL if the bounds specified by &drm_pvr_ioctl_vm_op_map_args.offset * and &drm_pvr_ioctl_vm_op_map_args.size are not valid or do not fall * within the buffer object specified by * &drm_pvr_ioctl_vm_op_map_args.handle, * * -%EINVAL if the bounds specified by * &drm_pvr_ioctl_vm_op_map_args.device_addr and * &drm_pvr_ioctl_vm_op_map_args.size do not form a valid device-virtual * address range which falls entirely within a single heap, or * * -%ENOENT if &drm_pvr_ioctl_vm_op_map_args.handle does not refer to a * valid PowerVR buffer object.
*/ staticint
pvr_ioctl_vm_map(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct pvr_device *pvr_dev = to_pvr_device(drm_dev); struct drm_pvr_ioctl_vm_map_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_vm_context *vm_ctx;
/* * Validate offset and size args. The alignment of these will be * checked when mapping; for now just check that they're within valid * bounds
*/ if (args->offset >= pvr_obj_size || offset_plus_size > pvr_obj_size) {
err = -EINVAL; goto err_put_pvr_object;
}
/* * In order to set up the mapping, we needed a reference to &pvr_obj. * However, pvr_vm_map() obtains and stores its own reference, so we * must release ours before returning.
*/
err_put_pvr_object:
pvr_gem_object_put(pvr_obj);
err_put_vm_context:
pvr_vm_context_put(vm_ctx);
err_drm_dev_exit:
drm_dev_exit(idx);
return err;
}
/** * pvr_ioctl_vm_unmap() - IOCTL to unmap buffer from GPU address space. * @drm_dev: [IN] DRM device. * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_vm_unmap_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_VM_UNMAP. * * Return: * * 0 on success, * * -%EINVAL if &drm_pvr_ioctl_vm_op_unmap_args.device_addr is not a valid * device page-aligned device-virtual address, or * * -%ENOENT if there is currently no PowerVR buffer object mapped at * &drm_pvr_ioctl_vm_op_unmap_args.device_addr.
*/ staticint
pvr_ioctl_vm_unmap(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_vm_unmap_args *args = raw_args; struct pvr_file *pvr_file = to_pvr_file(file); struct pvr_vm_context *vm_ctx; int err;
/* Initial validation of args. */ if (args->_padding_4) return -EINVAL;
vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); if (!vm_ctx) return -EINVAL;
/* * pvr_ioctl_submit_job() - IOCTL to submit a job to the GPU * @drm_dev: [IN] DRM device. * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type * &struct drm_pvr_ioctl_submit_job_args. * @file: [IN] DRM file private data. * * Called from userspace with %DRM_IOCTL_PVR_SUBMIT_JOB. * * Return: * * 0 on success, or * * -%EINVAL if arguments are invalid.
*/ staticint
pvr_ioctl_submit_jobs(struct drm_device *drm_dev, void *raw_args, struct drm_file *file)
{ struct drm_pvr_ioctl_submit_jobs_args *args = raw_args; struct pvr_device *pvr_dev = to_pvr_device(drm_dev); struct pvr_file *pvr_file = to_pvr_file(file); int idx; int err;
if (!drm_dev_enter(drm_dev, &idx)) return -EIO;
err = pvr_submit_jobs(pvr_dev, pvr_file, args);
drm_dev_exit(idx);
return err;
}
int
pvr_get_uobj(u64 usr_ptr, u32 usr_stride, u32 min_stride, u32 obj_size, void *out)
{ if (usr_stride < min_stride) return -EINVAL;
/* Drop references on any remaining objects. */
pvr_destroy_free_lists_for_file(pvr_file);
pvr_destroy_hwrt_datasets_for_file(pvr_file);
pvr_destroy_vm_contexts_for_file(pvr_file);
/* * This legacy compatible string was introduced early on before the more generic * "img,img-rogue" was added. Keep it around here for compatibility, but never use * "img,img-axe" in new devicetrees.
*/
{ .compatible = "img,img-axe", .data = NULL },
{}
};
MODULE_DEVICE_TABLE(of, dt_match);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.