// SPDX-License-Identifier: GPL-2.0-only OR MIT
/* Copyright (c) 2023 Imagination Technologies Ltd. */
#include "pvr_device.h"
#include "pvr_drv.h"
#include "pvr_gem.h"
#include "pvr_mmu.h"
#include "pvr_rogue_defs.h"
#include "pvr_rogue_fwif_client.h"
#include "pvr_rogue_fwif_shared.h"
#include "pvr_vm.h"
#include <uapi/drm/pvr_drm.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>
#include <drm/drm_ioctl.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
/**
* 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)
*/
/**
* 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()).
*/
static int
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);
struct pvr_gem_object *pvr_obj;
size_t sanitized_size;
int idx;
int err;
if (!drm_dev_enter(drm_dev, &idx))
return -EIO;
/* 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 (