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

Commit 9be23ae4 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'topic/core-stuff-2014-11-28' of git://anongit.freedesktop.org/drm-intel into drm-next

So here's a pile of atomic fixes and improvements from various people.
There's still more patches in-flight, so I think I'll keep collecting them
in a separate branch.

* tag 'topic/core-stuff-2014-11-28' of git://anongit.freedesktop.org/drm-intel:
  drm/atomic: clear plane's CRTC and FB when shutting down
  drm: Handle atomic state properly in kms getfoo ioctl
  drm: use mode_object_find helpers
  drm: fix indentation
  drm/msm: switch to atomic-helpers iterator macros
  drm/atomic: add plane iterator macros
  drm/atomic: track bitmask of planes attached to crtc
  drm: Free atomic state during cleanup
  drm: Make drm_atomic.h standalone includible
  drm: Make drm_atomic_helper.h standalone includible
  drm/plane: Add missing kerneldoc
  drm/plane: Pass old state to ->atomic_update()
  drm/atomic_helper: Cope with plane->crtc == NULL in disable helper
  drm/atomic: Drop per-plane locking TODO
  drm/atomic-helper: Skip vblank waits for unchanged fbs
  drm: Document that drm_dev_alloc doesn't need a parent
parents 5a0e9d72 e5b5341c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2343,6 +2343,7 @@ void intel_crt_init(struct drm_device *dev)
	<title>Atomic State Reset and Initialization</title>
!Pdrivers/gpu/drm/drm_atomic_helper.c atomic state reset and initialization
      </sect3>
!Iinclude/drm/drm_atomic_helper.h
!Edrivers/gpu/drm/drm_atomic_helper.c
    </sect2>
    <sect2>
+21 −11
Original line number Diff line number Diff line
@@ -243,12 +243,6 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
	if (state->plane_states[index])
		return state->plane_states[index];

	/*
	 * TODO: We currently don't have per-plane mutexes. So instead of trying
	 * crazy tricks with deferring plane->crtc and hoping for the best just
	 * grab all crtc locks. Once we have per-plane locks we must update this
	 * to only take the plane mutex.
	 */
	ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx);
	if (ret)
		return ERR_PTR(ret);
@@ -350,7 +344,8 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);

/**
 * drm_atomic_set_crtc_for_plane - set crtc for plane
 * @plane_state: atomic state object for the plane
 * @state: the incoming atomic state
 * @plane: the plane whose incoming state to update
 * @crtc: crtc to use for the plane
 *
 * Changing the assigned crtc for a plane requires us to grab the lock and state
@@ -363,20 +358,35 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
 * sequence must be restarted. All other errors are fatal.
 */
int
drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
			      struct drm_crtc *crtc)
drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
			      struct drm_plane *plane, struct drm_crtc *crtc)
{
	struct drm_plane_state *plane_state =
			drm_atomic_get_plane_state(state, plane);
	struct drm_crtc_state *crtc_state;

	if (WARN_ON(IS_ERR(plane_state)))
		return PTR_ERR(plane_state);

	if (plane_state->crtc) {
		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
						       plane_state->crtc);
		if (WARN_ON(IS_ERR(crtc_state)))
			return PTR_ERR(crtc_state);

		crtc_state->plane_mask &= ~(1 << drm_plane_index(plane));
	}

	plane_state->crtc = crtc;

	if (crtc) {
		crtc_state = drm_atomic_get_crtc_state(plane_state->state,
						       crtc);
		if (IS_ERR(crtc_state))
			return PTR_ERR(crtc_state);
		crtc_state->plane_mask |= (1 << drm_plane_index(plane));
	}

	plane_state->crtc = crtc;

	if (crtc)
		DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
			      plane_state, crtc->base.id);
+65 −12
Original line number Diff line number Diff line
@@ -751,6 +751,33 @@ static void wait_for_fences(struct drm_device *dev,
	}
}

static bool framebuffer_changed(struct drm_device *dev,
				struct drm_atomic_state *old_state,
				struct drm_crtc *crtc)
{
	struct drm_plane *plane;
	struct drm_plane_state *old_plane_state;
	int nplanes = old_state->dev->mode_config.num_total_plane;
	int i;

	for (i = 0; i < nplanes; i++) {
		plane = old_state->planes[i];
		old_plane_state = old_state->plane_states[i];

		if (!plane)
			continue;

		if (plane->state->crtc != crtc &&
		    old_plane_state->crtc != crtc)
			continue;

		if (plane->state->fb != old_plane_state->fb)
			return true;
	}

	return false;
}

/**
 * drm_atomic_helper_wait_for_vblanks - wait for vblank on crtcs
 * @dev: DRM device
@@ -758,7 +785,9 @@ static void wait_for_fences(struct drm_device *dev,
 *
 * Helper to, after atomic commit, wait for vblanks on all effected
 * crtcs (ie. before cleaning up old framebuffers using
 * drm_atomic_helper_cleanup_planes())
 * drm_atomic_helper_cleanup_planes()). It will only wait on crtcs where the
 * framebuffers have actually changed to optimize for the legacy cursor and
 * plane update use-case.
 */
void
drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
@@ -784,6 +813,9 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
		if (!crtc->state->enable)
			continue;

		if (!framebuffer_changed(dev, old_state, crtc))
			continue;

		ret = drm_crtc_vblank_get(crtc);
		if (ret != 0)
			continue;
@@ -1014,6 +1046,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
	for (i = 0; i < nplanes; i++) {
		struct drm_plane_helper_funcs *funcs;
		struct drm_plane *plane = old_state->planes[i];
		struct drm_plane_state *old_plane_state;

		if (!plane)
			continue;
@@ -1023,7 +1056,9 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
		if (!funcs || !funcs->atomic_update)
			continue;

		funcs->atomic_update(plane);
		old_plane_state = old_state->plane_states[i];

		funcs->atomic_update(plane, old_plane_state);
	}

	for (i = 0; i < ncrtcs; i++) {
@@ -1187,7 +1222,7 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
		goto fail;
	}

	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
	ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
	if (ret != 0)
		goto fail;
	drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1243,6 +1278,17 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
	struct drm_plane_state *plane_state;
	int ret = 0;

	/*
	 * FIXME: Without plane->crtc set we can't get at the implicit legacy
	 * acquire context. The real fix will be to wire the acquire ctx through
	 * everywhere we need it, but meanwhile prevent chaos by just skipping
	 * this noop. The critical case is the cursor ioctls which a) only grab
	 * crtc/cursor-plane locks (so we need the crtc to get at the right
	 * acquire context) and b) can try to disable the plane multiple times.
	 */
	if (!plane->crtc)
		return 0;

	state = drm_atomic_state_alloc(plane->dev);
	if (!state)
		return -ENOMEM;
@@ -1255,7 +1301,7 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
		goto fail;
	}

	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
	ret = drm_atomic_set_crtc_for_plane(state, plane, NULL);
	if (ret != 0)
		goto fail;
	drm_atomic_set_fb_for_plane(plane_state, NULL);
@@ -1406,11 +1452,24 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
		goto fail;
	}

	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
	if (IS_ERR(primary_state)) {
		ret = PTR_ERR(primary_state);
		goto fail;
	}

	if (!set->mode) {
		WARN_ON(set->fb);
		WARN_ON(set->num_connectors);

		crtc_state->enable = false;

		ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL);
		if (ret != 0)
			goto fail;

		drm_atomic_set_fb_for_plane(primary_state, NULL);

		goto commit;
	}

@@ -1420,13 +1479,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
	crtc_state->enable = true;
	drm_mode_copy(&crtc_state->mode, set->mode);

	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
	if (IS_ERR(primary_state)) {
		ret = PTR_ERR(primary_state);
		goto fail;
	}

	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
	ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc);
	if (ret != 0)
		goto fail;
	drm_atomic_set_fb_for_plane(primary_state, set->fb);
@@ -1698,7 +1751,7 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
		goto fail;
	}

	ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
	ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
	if (ret != 0)
		goto fail;
	drm_atomic_set_fb_for_plane(plane_state, fb);
+63 −12
Original line number Diff line number Diff line
@@ -721,6 +721,10 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
	drm_mode_object_put(dev, &crtc->base);
	list_del(&crtc->head);
	dev->mode_config.num_crtc--;

	WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
	if (crtc->state && crtc->funcs->atomic_destroy_state)
		crtc->funcs->atomic_destroy_state(crtc, crtc->state);
}
EXPORT_SYMBOL(drm_crtc_cleanup);

@@ -918,6 +922,11 @@ void drm_connector_cleanup(struct drm_connector *connector)
	connector->name = NULL;
	list_del(&connector->head);
	dev->mode_config.num_connector--;

	WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
	if (connector->state && connector->funcs->atomic_destroy_state)
		connector->funcs->atomic_destroy_state(connector,
						       connector->state);
}
EXPORT_SYMBOL(drm_connector_cleanup);

@@ -1244,6 +1253,10 @@ void drm_plane_cleanup(struct drm_plane *plane)
	if (plane->type == DRM_PLANE_TYPE_OVERLAY)
		dev->mode_config.num_overlay_plane--;
	drm_modeset_unlock_all(dev);

	WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
	if (plane->state && plane->funcs->atomic_destroy_state)
		plane->funcs->atomic_destroy_state(plane, plane->state);
}
EXPORT_SYMBOL(drm_plane_cleanup);

@@ -1955,6 +1968,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
	return true;
}

static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
{
	/* For atomic drivers only state objects are synchronously updated and
	 * protected by modeset locks, so check those first. */
	if (connector->state)
		return connector->state->best_encoder;
	return connector->encoder;
}

/**
 * drm_mode_getconnector - get connector configuration
 * @dev: drm device for the ioctl
@@ -1973,6 +1995,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
{
	struct drm_mode_get_connector *out_resp = data;
	struct drm_connector *connector;
	struct drm_encoder *encoder;
	struct drm_display_mode *mode;
	int mode_count = 0;
	int props_count = 0;
@@ -2028,8 +2051,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
	out_resp->subpixel = connector->display_info.subpixel_order;
	out_resp->connection = connector->status;
	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
	if (connector->encoder)
		out_resp->encoder_id = connector->encoder->base.id;

	encoder = drm_connector_get_encoder(connector);
	if (encoder)
		out_resp->encoder_id = encoder->base.id;
	else
		out_resp->encoder_id = 0;
	drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -2099,6 +2124,33 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
	return ret;
}

static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
{
	struct drm_connector *connector;
	struct drm_device *dev = encoder->dev;
	bool uses_atomic = false;

	/* For atomic drivers only state objects are synchronously updated and
	 * protected by modeset locks, so check those first. */
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (!connector->state)
			continue;

		uses_atomic = true;

		if (connector->state->best_encoder != encoder)
			continue;

		return connector->state->crtc;
	}

	/* Don't return stale data (e.g. pending async disable). */
	if (uses_atomic)
		return NULL;

	return encoder->crtc;
}

/**
 * drm_mode_getencoder - get encoder configuration
 * @dev: drm device for the ioctl
@@ -2117,6 +2169,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
{
	struct drm_mode_get_encoder *enc_resp = data;
	struct drm_encoder *encoder;
	struct drm_crtc *crtc;

	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EINVAL;
@@ -2126,7 +2179,10 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
		return -ENOENT;

	drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
	if (encoder->crtc)
	crtc = drm_encoder_get_crtc(encoder);
	if (crtc)
		enc_resp->crtc_id = crtc->base.id;
	else if (encoder->crtc)
		enc_resp->crtc_id = encoder->crtc->base.id;
	else
		enc_resp->crtc_id = 0;
@@ -2392,7 +2448,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
		      struct drm_file *file_priv)
{
	struct drm_mode_set_plane *plane_req = data;
	struct drm_mode_object *obj;
	struct drm_plane *plane;
	struct drm_crtc *crtc = NULL;
	struct drm_framebuffer *fb = NULL;
@@ -2415,14 +2470,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
	 * First, find the plane, crtc, and fb objects.  If not available,
	 * we don't bother to call the driver.
	 */
	obj = drm_mode_object_find(dev, plane_req->plane_id,
				   DRM_MODE_OBJECT_PLANE);
	if (!obj) {
	plane = drm_plane_find(dev, plane_req->plane_id);
	if (!plane) {
		DRM_DEBUG_KMS("Unknown plane ID %d\n",
			      plane_req->plane_id);
		return -ENOENT;
	}
	plane = obj_to_plane(obj);

	if (plane_req->fb_id) {
		fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
@@ -2432,14 +2485,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
			return -ENOENT;
		}

		obj = drm_mode_object_find(dev, plane_req->crtc_id,
					   DRM_MODE_OBJECT_CRTC);
		if (!obj) {
		crtc = drm_crtc_find(dev, plane_req->crtc_id);
		if (!crtc) {
			DRM_DEBUG_KMS("Unknown crtc ID %d\n",
				      plane_req->crtc_id);
			return -ENOENT;
		}
		crtc = obj_to_crtc(obj);
	}

	/*
+2 −0
Original line number Diff line number Diff line
@@ -535,6 +535,8 @@ static void drm_fs_inode_free(struct inode *inode)
 * The initial ref-count of the object is 1. Use drm_dev_ref() and
 * drm_dev_unref() to take and drop further ref-counts.
 *
 * Note that for purely virtual devices @parent can be NULL.
 *
 * RETURNS:
 * Pointer to new DRM device, or NULL if out of memory.
 */
Loading