Skip to content

Commit

Permalink
Merge tag 'topic/core-stuff-2014-11-28' of git://anongit.freedesktop.…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Dave Airlie committed Dec 1, 2014
2 parents 5a0e9d7 + e5b5341 commit 9be23ae
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 75 deletions.
1 change: 1 addition & 0 deletions Documentation/DocBook/drm.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
32 changes: 21 additions & 11 deletions drivers/gpu/drm/drm_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
77 changes: 65 additions & 12 deletions drivers/gpu/drm/drm_atomic_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,14 +751,43 @@ 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
* @old_state: atomic state object with old state structures
*
* 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,
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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++) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
75 changes: 63 additions & 12 deletions drivers/gpu/drm/drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
}

/*
Expand Down
Loading

0 comments on commit 9be23ae

Please sign in to comment.