diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_drv.c')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 94 | 
1 files changed, 92 insertions, 2 deletions
| diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 3f217b578293..50b65ffc24b1 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -37,9 +37,10 @@   * - 1.9.0 - Add MSM_SUBMIT_FENCE_SN_IN   * - 1.10.0 - Add MSM_SUBMIT_BO_NO_IMPLICIT   * - 1.11.0 - Add wait boost (MSM_WAIT_FENCE_BOOST, MSM_PREP_BOOST) + * - 1.12.0 - Add MSM_INFO_SET_METADATA and MSM_INFO_GET_METADATA   */  #define MSM_VERSION_MAJOR	1 -#define MSM_VERSION_MINOR	10 +#define MSM_VERSION_MINOR	12  #define MSM_VERSION_PATCHLEVEL	0  static void msm_deinit_vram(struct drm_device *ddev); @@ -544,6 +545,85 @@ static int msm_ioctl_gem_info_set_iova(struct drm_device *dev,  	return msm_gem_set_iova(obj, ctx->aspace, iova);  } +static int msm_ioctl_gem_info_set_metadata(struct drm_gem_object *obj, +					   __user void *metadata, +					   u32 metadata_size) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	void *buf; +	int ret; + +	/* Impose a moderate upper bound on metadata size: */ +	if (metadata_size > 128) { +		return -EOVERFLOW; +	} + +	/* Use a temporary buf to keep copy_from_user() outside of gem obj lock: */ +	buf = memdup_user(metadata, metadata_size); +	if (IS_ERR(buf)) +		return PTR_ERR(buf); + +	ret = msm_gem_lock_interruptible(obj); +	if (ret) +		goto out; + +	msm_obj->metadata = +		krealloc(msm_obj->metadata, metadata_size, GFP_KERNEL); +	msm_obj->metadata_size = metadata_size; +	memcpy(msm_obj->metadata, buf, metadata_size); + +	msm_gem_unlock(obj); + +out: +	kfree(buf); + +	return ret; +} + +static int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, +					   __user void *metadata, +					   u32 *metadata_size) +{ +	struct msm_gem_object *msm_obj = to_msm_bo(obj); +	void *buf; +	int ret, len; + +	if (!metadata) { +		/* +		 * Querying the size is inherently racey, but +		 * EXT_external_objects expects the app to confirm +		 * via device and driver UUIDs that the exporter and +		 * importer versions match.  All we can do from the +		 * kernel side is check the length under obj lock +		 * when userspace tries to retrieve the metadata +		 */ +		*metadata_size = msm_obj->metadata_size; +		return 0; +	} + +	ret = msm_gem_lock_interruptible(obj); +	if (ret) +		return ret; + +	/* Avoid copy_to_user() under gem obj lock: */ +	len = msm_obj->metadata_size; +	buf = kmemdup(msm_obj->metadata, len, GFP_KERNEL); + +	msm_gem_unlock(obj); + +	if (*metadata_size < len) { +		ret = -ETOOSMALL; +	} else if (copy_to_user(metadata, buf, len)) { +		ret = -EFAULT; +	} else { +		*metadata_size = len; +	} + +	kfree(buf); + +	return 0; +} +  static int msm_ioctl_gem_info(struct drm_device *dev, void *data,  		struct drm_file *file)  { @@ -566,6 +646,8 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,  		break;  	case MSM_INFO_SET_NAME:  	case MSM_INFO_GET_NAME: +	case MSM_INFO_SET_METADATA: +	case MSM_INFO_GET_METADATA:  		break;  	default:  		return -EINVAL; @@ -618,7 +700,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,  		break;  	case MSM_INFO_GET_NAME:  		if (args->value && (args->len < strlen(msm_obj->name))) { -			ret = -EINVAL; +			ret = -ETOOSMALL;  			break;  		}  		args->len = strlen(msm_obj->name); @@ -628,6 +710,14 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,  				ret = -EFAULT;  		}  		break; +	case MSM_INFO_SET_METADATA: +		ret = msm_ioctl_gem_info_set_metadata( +			obj, u64_to_user_ptr(args->value), args->len); +		break; +	case MSM_INFO_GET_METADATA: +		ret = msm_ioctl_gem_info_get_metadata( +			obj, u64_to_user_ptr(args->value), &args->len); +		break;  	}  	drm_gem_object_put(obj); | 
