Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 165e5ffa authored by Rahul Sharma's avatar Rahul Sharma Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm: support release/retire fence through set prop



Multiple drm clients are allowed to call the
get_properties on drm device node. If sde driver
creates the fence for each get_property call then
it may leave fd leak in client process context
because might not be expecting fences. Supporting
get_property for only master device may not solve
the issue because master client may still call
the get_properties multiple times between two
commit cycles.
This patch supports release/retire fence through
set property to avoid fence leak.

Change-Id: I07fe63fe84901d7f96b522ca6309cfdd90a25c40
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
Signed-off-by: default avatarRahul Sharma <rahsha@codeaurora.org>
parent 5b964b49
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -428,6 +428,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
	struct sde_connector *c_conn;
	struct sde_connector_state *c_state;
	int idx, rc;
	uint64_t fence_fd = 0;

	if (!connector || !state || !property) {
		SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n",
@@ -472,6 +473,23 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
				SDE_ERROR("prep fb failed, %d\n", rc);
		}
		break;
	case CONNECTOR_PROP_RETIRE_FENCE:
		rc = sde_fence_create(&c_conn->retire_fence, &fence_fd, 0);
		if (rc) {
			SDE_ERROR("fence create failed rc:%d\n", rc);
			goto end;
		}

		rc = copy_to_user((uint64_t __user *)val, &fence_fd,
			sizeof(uint64_t));
		if (rc) {
			SDE_ERROR("copy to user failed rc:%d\n", rc);
			/* fence will be released with timeline update */
			put_unused_fd(fence_fd);
			rc = -EFAULT;
			goto end;
		}
		break;
	case CONNECTOR_PROP_TOPOLOGY_CONTROL:
		rc = sde_rm_check_property_topctl(val);
		if (rc)
@@ -931,8 +949,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
		"hdr_control", 0x0, 0, ~0, 0,
		CONNECTOR_PROP_HDR_CONTROL);

	msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
			0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
	msm_property_install_volatile_range(&c_conn->property_info,
		"RETIRE_FENCE", 0x0, 0, ~0, 0, CONNECTOR_PROP_RETIRE_FENCE);

	msm_property_install_volatile_signed_range(&c_conn->property_info,
			"PLL_DELTA", 0x0, INT_MIN, INT_MAX, 0,
+81 −38
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved.
 * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
@@ -1642,8 +1642,8 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
		"input_fence_timeout", 0x0, 0, SDE_CRTC_MAX_INPUT_FENCE_TIMEOUT,
		SDE_CRTC_INPUT_FENCE_TIMEOUT, CRTC_PROP_INPUT_FENCE_TIMEOUT);

	msm_property_install_range(&sde_crtc->property_info, "output_fence",
			0x0, 0, INR_OPEN_MAX, 0x0, CRTC_PROP_OUTPUT_FENCE);
	msm_property_install_volatile_range(&sde_crtc->property_info,
		"output_fence", 0x0, 0, ~0, 0, CRTC_PROP_OUTPUT_FENCE);

	msm_property_install_range(&sde_crtc->property_info,
			"output_fence_offset", 0x0, 0, 1, 0,
@@ -1708,6 +1708,21 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
	kfree(info);
}

static int _sde_crtc_get_output_fence(struct drm_crtc *crtc,
	const struct drm_crtc_state *state, uint64_t *val)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *cstate;
	uint32_t offset;

	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(state);

	offset = sde_crtc_get_property(cstate, CRTC_PROP_OUTPUT_FENCE_OFFSET);

	return sde_fence_create(&sde_crtc->output_fence, val, offset);
}

/**
 * sde_crtc_atomic_set_property - atomically set a crtc drm property
 * @crtc: Pointer to drm crtc structure
@@ -1724,27 +1739,57 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc,
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *cstate;
	int idx, ret = -EINVAL;
	 uint64_t fence_fd = 0;

	if (!crtc || !state || !property) {
		SDE_ERROR("invalid argument(s)\n");
	} else {
		return -EINVAL;
	}

	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(state);

	ret = msm_property_atomic_set(&sde_crtc->property_info,
			cstate->property_values, cstate->property_blobs,
			property, val);

	if (!ret) {
		idx = msm_property_index(&sde_crtc->property_info,
				property);
			if (idx == CRTC_PROP_INPUT_FENCE_TIMEOUT)
		switch (idx) {
		case CRTC_PROP_INPUT_FENCE_TIMEOUT:
			_sde_crtc_set_input_fence_timeout(cstate);
			break;
		case CRTC_PROP_OUTPUT_FENCE:
			ret = _sde_crtc_get_output_fence(crtc,
						state, &fence_fd);
			if (ret) {
				SDE_ERROR("fence create failed rc:%d\n", ret);
				goto exit;
			}

			ret  = copy_to_user((uint64_t __user *)val, &fence_fd,
					sizeof(uint64_t));

			if (ret) {
				SDE_ERROR("copy to user failed rc:%d\n", ret);
				put_unused_fd(fence_fd);
				ret = -EFAULT;
				goto exit;
			}
			break;
		default:
			/* nothing to do */
			break;
		}
	} else {
		ret = sde_cp_crtc_set_property(crtc,
				property, val);
	}

exit:
	if (ret)
		DRM_ERROR("failed to set the property\n");
	}

	return ret;
}
@@ -1783,17 +1828,15 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,

	if (!crtc || !state) {
		SDE_ERROR("invalid argument(s)\n");
	} else {
		return -EINVAL;
	}

	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(state);

	i = msm_property_index(&sde_crtc->property_info, property);
	if (i == CRTC_PROP_OUTPUT_FENCE) {
			int offset = sde_crtc_get_property(cstate,
					CRTC_PROP_OUTPUT_FENCE_OFFSET);

			ret = sde_fence_create(&sde_crtc->output_fence, val,
							offset);
		ret = _sde_crtc_get_output_fence(crtc, state, val);
		if (ret)
			SDE_ERROR("fence create failed\n");
	} else {
@@ -1806,7 +1849,7 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,
	}
	if (ret)
		DRM_ERROR("get property failed\n");
	}

	return ret;
}