From: Rob Clark <robdclark@gmail.com>
To: dri-devel@lists.freedesktop.org
Subject: [RFCv3 11/14] drm: convert crtc to properties/state
Date: Wed, 20 Nov 2013 15:48:10 -0500 [thread overview]
Message-ID: <1384980493-25499-12-git-send-email-robdclark@gmail.com> (raw)
In-Reply-To: <1384980493-25499-1-git-send-email-robdclark@gmail.com>
Break the mutable state of a crtc out into a separate structure
and use atomic properties mechanism to set crtc attributes. This
makes it easier to have some helpers for crtc->set_property()
and for checking for invalid params. The idea is that individual
drivers can wrap the state struct in their own struct which adds
driver specific parameters, for easy build-up of state across
multiple set_property() calls and for easy atomic commit or roll-
back.
This also re-works the locking a bit.. maybe some of these changes
should be rejuggled into different patch. But now atomic plane updates
grab current (and if necessary, incoming) crtc locks for their
synchronization.
---
drivers/gpu/drm/ast/ast_mode.c | 1 +
drivers/gpu/drm/cirrus/cirrus_mode.c | 1 +
drivers/gpu/drm/drm_atomic_helper.c | 347 ++++++++++++++++-
drivers/gpu/drm/drm_crtc.c | 580 +++++++++++++++++------------
drivers/gpu/drm/drm_fb_cma_helper.c | 9 +-
drivers/gpu/drm/drm_fb_helper.c | 12 +-
drivers/gpu/drm/exynos/exynos_drm_crtc.c | 5 +-
drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 4 +-
drivers/gpu/drm/gma500/cdv_intel_display.c | 1 +
drivers/gpu/drm/gma500/psb_drv.c | 4 +-
drivers/gpu/drm/gma500/psb_intel_display.c | 1 +
drivers/gpu/drm/i915/intel_display.c | 17 +-
drivers/gpu/drm/i915/intel_fbdev.c | 6 +-
drivers/gpu/drm/mgag200/mgag200_mode.c | 1 +
drivers/gpu/drm/msm/mdp4/mdp4_crtc.c | 5 +-
drivers/gpu/drm/msm/msm_drv.c | 7 +-
drivers/gpu/drm/nouveau/dispnv04/crtc.c | 1 +
drivers/gpu/drm/nouveau/nv50_display.c | 1 +
drivers/gpu/drm/omapdrm/omap_crtc.c | 17 +-
drivers/gpu/drm/omapdrm/omap_drv.c | 6 +-
drivers/gpu/drm/qxl/qxl_display.c | 2 +
drivers/gpu/drm/radeon/radeon_display.c | 2 +
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 2 +
drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +
drivers/gpu/drm/tegra/fb.c | 7 +-
drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 1 +
drivers/gpu/drm/udl/udl_modeset.c | 2 +
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 12 +-
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 1 +
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 1 +
include/drm/drm_atomic_helper.h | 41 ++
include/drm/drm_crtc.h | 87 ++++-
include/drm/drm_fb_helper.h | 3 +-
include/uapi/drm/drm_mode.h | 2 +
34 files changed, 864 insertions(+), 327 deletions(-)
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 7fc9f72..13f6943 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -619,6 +619,7 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
.cursor_move = ast_cursor_move,
.reset = ast_crtc_reset,
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.gamma_set = ast_crtc_gamma_set,
.destroy = ast_crtc_destroy,
};
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index adabc3d..9e0b713 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -363,6 +363,7 @@ static void cirrus_crtc_destroy(struct drm_crtc *crtc)
static const struct drm_crtc_funcs cirrus_crtc_funcs = {
.gamma_set = cirrus_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = cirrus_crtc_destroy,
};
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 0618113..aaab456 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -40,17 +40,22 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
{
struct drm_atomic_helper_state *state;
int nplanes = dev->mode_config.num_plane;
+ int ncrtcs = dev->mode_config.num_crtc;
int sz;
void *ptr;
sz = sizeof(*state);
sz += (sizeof(state->planes) + sizeof(state->pstates)) * nplanes;
+ sz += (sizeof(state->crtcs) + sizeof(state->cstates)) * ncrtcs;
ptr = kzalloc(sz, GFP_KERNEL);
state = ptr;
ptr = &state[1];
+ ww_acquire_init(&state->ww_ctx, &crtc_ww_class);
+ INIT_LIST_HEAD(&state->locked_crtcs);
+
kref_init(&state->refcount);
state->dev = dev;
state->flags = flags;
@@ -61,6 +66,12 @@ void *drm_atomic_helper_begin(struct drm_device *dev, uint32_t flags)
state->pstates = ptr;
ptr = &state->pstates[nplanes];
+ state->crtcs = ptr;
+ ptr = &state->crtcs[ncrtcs];
+
+ state->cstates = ptr;
+ ptr = &state->cstates[ncrtcs];
+
return state;
}
EXPORT_SYMBOL(drm_atomic_helper_begin);
@@ -79,7 +90,16 @@ int drm_atomic_helper_set_event(struct drm_device *dev,
void *state, struct drm_mode_object *obj,
struct drm_pending_vblank_event *event)
{
- return -EINVAL; /* for now */
+ switch (obj->type) {
+ case DRM_MODE_OBJECT_CRTC: {
+ struct drm_crtc_state *cstate =
+ drm_atomic_get_crtc_state(obj_to_crtc(obj), state);
+ cstate->event = event;
+ return 0;
+ }
+ default:
+ return -EINVAL;
+ }
}
EXPORT_SYMBOL(drm_atomic_helper_set_event);
@@ -98,6 +118,7 @@ int drm_atomic_helper_check(struct drm_device *dev, void *state)
{
struct drm_atomic_helper_state *a = state;
int nplanes = dev->mode_config.num_plane;
+ int ncrtcs = dev->mode_config.num_crtc;
int i, ret = 0;
for (i = 0; i < nplanes; i++) {
@@ -108,10 +129,55 @@ int drm_atomic_helper_check(struct drm_device *dev, void *state)
}
}
+ for (i = 0; i < ncrtcs; i++) {
+ if (a->crtcs[i]) {
+ ret = drm_atomic_check_crtc_state(a->crtcs[i], a->cstates[i]);
+ if (ret)
+ break;
+ }
+ }
+
return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_check);
+static void drop_locks(struct drm_atomic_helper_state *a)
+{
+ ww_acquire_done(&a->ww_ctx);
+ while (!list_empty(&a->locked_crtcs)) {
+ struct drm_crtc *crtc;
+
+ crtc = list_first_entry(&a->locked_crtcs,
+ struct drm_crtc, lock_head);
+
+ drm_modeset_unlock_crtc(crtc);
+ }
+ ww_acquire_fini(&a->ww_ctx);
+}
+
+static int grab_locks(struct drm_atomic_helper_state *a)
+{
+ int nplanes = a->dev->mode_config.num_plane;
+ int ncrtcs = a->dev->mode_config.num_crtc;
+ int i;
+
+ for (i = 0; i < nplanes; i++) {
+ if (a->planes[i]) {
+ /* both incoming and outgoing crtc: */
+ if (a->planes[i]->state->crtc)
+ drm_modeset_lock_crtc(a->planes[i]->state->crtc, a);
+ if (a->pstates[i]->crtc)
+ drm_modeset_lock_crtc(a->pstates[i]->crtc, a);
+ }
+ }
+
+ for (i = 0; i < ncrtcs; i++)
+ if (a->crtcs[i])
+ drm_modeset_lock_crtc(a->crtcs[i], a);
+
+ return 0;
+}
+
/**
* drm_atomic_helper_commit - commit state
* @dev: DRM device
@@ -127,8 +193,18 @@ int drm_atomic_helper_commit(struct drm_device *dev, void *state)
{
struct drm_atomic_helper_state *a = state;
int nplanes = dev->mode_config.num_plane;
+ int ncrtcs = dev->mode_config.num_crtc;
int i, ret = 0;
+ /* re-acquire dropped locks, in case of NONBLOCK */
+ mutex_lock(&a->dev->struct_mutex);
+ if (a->locks_dropped) {
+ ww_acquire_init(&a->ww_ctx, &crtc_ww_class);
+ grab_locks(a);
+ a->locks_dropped = false;
+ }
+ mutex_unlock(&a->dev->struct_mutex);
+
for (i = 0; i < nplanes; i++) {
if (a->planes[i]) {
ret = drm_atomic_commit_plane_state(a->planes[i], a->pstates[i]);
@@ -137,6 +213,14 @@ int drm_atomic_helper_commit(struct drm_device *dev, void *state)
}
}
+ for (i = 0; i < ncrtcs; i++) {
+ if (a->crtcs[i]) {
+ ret = drm_atomic_commit_crtc_state(a->crtcs[i], a->cstates[i]);
+ if (ret)
+ break;
+ }
+ }
+
return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_commit);
@@ -150,26 +234,51 @@ EXPORT_SYMBOL(drm_atomic_helper_commit);
*/
void drm_atomic_helper_end(struct drm_device *dev, void *state)
{
+ struct drm_atomic_helper_state *a = state;
+
+ /* yes, we need to synchronize our locks! So we don't race with
+ * driver calling back drm_atomic_helper_commit() asynchronously
+ * in NONBLOCK case
+ */
+ mutex_lock(&a->dev->struct_mutex);
+ drop_locks(a);
+ a->locks_dropped = true;
+ mutex_unlock(&a->dev->struct_mutex);
+
drm_atomic_helper_state_unreference(state);
}
EXPORT_SYMBOL(drm_atomic_helper_end);
void _drm_atomic_helper_state_free(struct kref *kref)
{
- struct drm_atomic_helper_state *state =
+ struct drm_atomic_helper_state *a =
container_of(kref, struct drm_atomic_helper_state, refcount);
- struct drm_device *dev = state->dev;
+ struct drm_device *dev = a->dev;
int nplanes = dev->mode_config.num_plane;
+ int ncrtcs = dev->mode_config.num_crtc;
int i;
for (i = 0; i < nplanes; i++) {
- if (state->pstates[i]) {
- state->planes[i]->state->state = NULL;
- kfree(state->pstates[i]);
+ if (a->pstates[i]) {
+ a->planes[i]->state->state = NULL;
+ kfree(a->pstates[i]);
}
}
- kfree(state);
+ for (i = 0; i < ncrtcs; i++) {
+ if (a->cstates[i]) {
+ a->crtcs[i]->state->state = NULL;
+ kfree(a->cstates[i]);
+ }
+ }
+
+ /* drop any locks we may have re-acquired (ie. NONBLOCK case,
+ * if the driver defers commit to a worker)
+ */
+ if (!a->locks_dropped)
+ drop_locks(a);
+
+ kfree(a);
}
EXPORT_SYMBOL(_drm_atomic_helper_state_free);
@@ -195,13 +304,21 @@ static struct drm_plane_state *
drm_atomic_helper_get_plane_state(struct drm_plane *plane, void *state)
{
struct drm_atomic_helper_state *a = state;
- struct drm_plane_state *pstate = a->pstates[plane->id];
+ struct drm_plane_state *pstate;
+
+ /* grab lock of current crtc: */
+ if (plane->state->crtc)
+ drm_modeset_lock_crtc(plane->state->crtc, state);
+
+ pstate = a->pstates[plane->id];
+
if (!pstate) {
pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
drm_atomic_helper_init_plane_state(plane, pstate, state);
a->planes[plane->id] = plane;
a->pstates[plane->id] = pstate;
}
+
return pstate;
}
@@ -216,15 +333,9 @@ static int
drm_atomic_helper_commit_plane_state(struct drm_plane *plane,
struct drm_plane_state *pstate)
{
- struct drm_device *dev = plane->dev;
struct drm_framebuffer *old_fb = NULL, *fb = NULL;
int ret = 0;
- /* probably more fine grain locking would be ok of old crtc
- * and new crtc were same..
- */
- drm_modeset_lock_all(dev);
-
fb = pstate->fb;
if (pstate->crtc && fb) {
@@ -250,8 +361,210 @@ drm_atomic_helper_commit_plane_state(struct drm_plane *plane,
swap_plane_state(plane, pstate->state);
}
- drm_modeset_unlock_all(dev);
+ if (fb)
+ drm_framebuffer_unreference(fb);
+ if (old_fb)
+ drm_framebuffer_unreference(old_fb);
+
+ return ret;
+}
+
+int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data)
+{
+ return drm_crtc_set_property(crtc,
+ drm_atomic_get_crtc_state(crtc, state),
+ property, val, blob_data);
+}
+EXPORT_SYMBOL(drm_atomic_helper_crtc_set_property);
+
+void drm_atomic_helper_init_crtc_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *cstate, void *state)
+{
+ /* snapshot current state: */
+ *cstate = *crtc->state;
+ cstate->state = state;
+
+ /* this should never happen.. but make sure! */
+ WARN_ON(cstate->event);
+ cstate->event = NULL;
+}
+EXPORT_SYMBOL(drm_atomic_helper_init_crtc_state);
+
+static struct drm_crtc_state *
+drm_atomic_helper_get_crtc_state(struct drm_crtc *crtc, void *state)
+{
+ struct drm_atomic_helper_state *a = state;
+ struct drm_crtc_state *cstate;
+
+ drm_modeset_lock_crtc(crtc, state);
+
+ cstate = a->cstates[crtc->id];
+
+ if (!cstate) {
+ cstate = kmalloc(sizeof(*cstate), GFP_KERNEL);
+ if (!cstate)
+ return NULL;
+ drm_atomic_helper_init_crtc_state(crtc, cstate, state);
+ a->crtcs[crtc->id] = crtc;
+ a->cstates[crtc->id] = cstate;
+ }
+ return cstate;
+}
+
+static void
+swap_crtc_state(struct drm_crtc *crtc, struct drm_atomic_helper_state *a)
+{
+ struct drm_crtc_state *cstate = a->cstates[crtc->id];
+ struct drm_device *dev = crtc->dev;
+ struct drm_pending_vblank_event *event = cstate->event;
+ if (event) {
+ /* hrm, need to sort out a better way to send events for
+ * other-than-pageflip.. but modeset is not async, so:
+ */
+ unsigned long flags;
+ spin_lock_irqsave(&dev->event_lock, flags);
+ drm_send_vblank_event(dev, crtc->id, event);
+ cstate->event = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+ swap(crtc->state, a->cstates[crtc->id]);
+ crtc->base.propvals = &crtc->state->propvals;
+}
+
+static struct drm_connector **get_connector_set(struct drm_device *dev,
+ uint32_t *connector_ids, uint32_t num_connector_ids)
+{
+ struct drm_connector **connector_set = NULL;
+ int i;
+
+ connector_set = kmalloc(num_connector_ids *
+ sizeof(struct drm_connector *),
+ GFP_KERNEL);
+ if (!connector_set)
+ return NULL;
+
+ for (i = 0; i < num_connector_ids; i++)
+ connector_set[i] = drm_connector_find(dev, connector_ids[i]);
+
+ return connector_set;
+}
+
+static struct drm_display_mode *get_mode(struct drm_crtc *crtc, struct drm_crtc_state *cstate)
+{
+ struct drm_display_mode *mode = NULL;
+ if (cstate->mode_valid) {
+ struct drm_device *dev = crtc->dev;
+ int ret;
+
+ mode = drm_mode_create(dev);
+ if (!mode)
+ return ERR_PTR(-ENOMEM);
+
+ ret = drm_crtc_convert_umode(mode, &cstate->mode);
+ if (ret) {
+ DRM_DEBUG_KMS("Invalid mode\n");
+ drm_mode_destroy(dev, mode);
+ return ERR_PTR(ret);
+ }
+
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ }
+ return mode;
+}
+static int set_config(struct drm_crtc *crtc, struct drm_crtc_state *cstate)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_framebuffer *fb = cstate->fb;
+ struct drm_connector **connector_set = get_connector_set(crtc->dev,
+ cstate->connector_ids, cstate->num_connector_ids);
+ struct drm_display_mode *mode = get_mode(crtc, cstate);
+ struct drm_mode_set set = {
+ .crtc = crtc,
+ .x = cstate->x,
+ .y = cstate->y,
+ .mode = mode,
+ .num_connectors = cstate->num_connector_ids,
+ .connectors = connector_set,
+ .fb = fb,
+ };
+ int ret;
+
+ if (IS_ERR(mode)) {
+ ret = PTR_ERR(mode);
+ return ret;
+ }
+
+ ret = drm_mode_set_config_internal(&set);
+ if (!ret)
+ swap_crtc_state(crtc, cstate->state);
+
+ if (fb)
+ drm_framebuffer_unreference(fb);
+
+ kfree(connector_set);
+ if (mode)
+ drm_mode_destroy(dev, mode);
+ return ret;
+}
+
+static int
+drm_atomic_helper_commit_crtc_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *cstate)
+{
+ struct drm_framebuffer *old_fb = NULL, *fb = NULL;
+ struct drm_atomic_helper_state *a = cstate->state;
+ int ret = -EINVAL;
+
+ if (cstate->set_config) {
+ cstate->set_config = false;
+ return set_config(crtc, cstate);
+ }
+
+ if (cstate->fb) {
+ /* pageflip */
+
+ if (crtc->fb == NULL) {
+ /* The framebuffer is currently unbound, presumably
+ * due to a hotplug event, that userspace has not
+ * yet discovered.
+ */
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (crtc->funcs->page_flip == NULL)
+ goto out;
+
+ old_fb = crtc->fb;
+ fb = cstate->fb;
+
+ ret = crtc->funcs->page_flip(crtc, fb, cstate->event, a->flags);
+ if (ret) {
+ /* Keep the old fb, don't unref it. */
+ old_fb = NULL;
+ } else {
+ cstate->event = NULL;
+ swap_crtc_state(crtc, cstate->state);
+ /* Unref only the old framebuffer. */
+ fb = NULL;
+ }
+ } else {
+ /* disable */
+ struct drm_mode_set set = {
+ .crtc = crtc,
+ .fb = NULL,
+ };
+
+ old_fb = crtc->state->fb;
+ ret = drm_mode_set_config_internal(&set);
+ if (!ret) {
+ swap_crtc_state(crtc, cstate->state);
+ }
+ }
+
+out:
if (fb)
drm_framebuffer_unreference(fb);
if (old_fb)
@@ -264,5 +577,9 @@ const struct drm_atomic_helper_funcs drm_atomic_helper_funcs = {
.get_plane_state = drm_atomic_helper_get_plane_state,
.check_plane_state = drm_plane_check_state,
.commit_plane_state = drm_atomic_helper_commit_plane_state,
+
+ .get_crtc_state = drm_atomic_helper_get_crtc_state,
+ .check_crtc_state = drm_crtc_check_state,
+ .commit_crtc_state = drm_atomic_helper_commit_crtc_state,
};
EXPORT_SYMBOL(drm_atomic_helper_funcs);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index b68984b..4b40a39 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -37,6 +37,53 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_atomic_helper.h>
+
+/**
+ * drm_modeset_lock_crtc - take crtc modeset lock
+ * @crtc: crtc to lock
+ * @state: atomic state
+ *
+ * If state is not NULL, then then it's aquire context is used
+ * and the crtc does not need to be explicitly unlocked, it
+ * will be automatically unlocked when the atomic update is
+ * complete (ioctl returns)
+ */
+int drm_modeset_lock_crtc(struct drm_crtc *crtc, void *state)
+{
+ // ugg, this makes atomic_helper mandatory.. not really
+ // sure yet whether I should care, or just simplify things
+ // and require that drivers use or extend atomic_helper:
+ struct drm_atomic_helper_state *a = state;
+ struct ww_acquire_ctx *ww_ctx = NULL;
+ int ret;
+
+ if (a) {
+ if (a->flags & DRM_MODE_ATOMIC_NOLOCK)
+ return 0;
+ ww_ctx = &a->ww_ctx;
+ }
+
+ ret = ww_mutex_lock(&crtc->mutex, ww_ctx);
+ if (a && !ret) {
+ WARN_ON(!list_empty(&crtc->lock_head));
+ list_add(&crtc->lock_head, &a->locked_crtcs);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_modeset_lock_crtc);
+
+/**
+ * drm_modeset_unlock_crtc - drop crtc modeset lock
+ * @crtc: crtc to unlock
+ */
+void drm_modeset_unlock_crtc(struct drm_crtc *crtc)
+{
+ list_del_init(&crtc->lock_head);
+ ww_mutex_unlock(&crtc->mutex);
+}
+EXPORT_SYMBOL(drm_modeset_unlock_crtc);
/**
* drm_modeset_lock_all - take all modeset locks
@@ -576,8 +623,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
struct drm_device *dev = fb->dev;
struct drm_crtc *crtc;
struct drm_plane *plane;
- struct drm_mode_set set;
- int ret;
WARN_ON(!list_empty(&fb->filp_head));
@@ -597,6 +642,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
* in this manner.
*/
if (atomic_read(&fb->refcount.refcount) > 1) {
+ struct drm_mode_config *config = &fb->dev->mode_config;
void *state;
state = dev->driver->atomic_begin(dev, 0);
@@ -605,22 +651,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
return;
}
- /* TODO once CRTC is converted to state/properties, we can push the
- * locking down into drm_atomic_helper_commit(), since that is where
- * the actual changes take place..
- */
- drm_modeset_lock_all(dev);
-
/* remove from any CRTC */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb == fb) {
/* should turn off the crtc */
- memset(&set, 0, sizeof(struct drm_mode_set));
- set.crtc = crtc;
- set.fb = NULL;
- ret = drm_mode_set_config_internal(&set);
- if (ret)
- DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+ drm_mode_crtc_set_obj_prop(crtc, state,
+ config->prop_fb_id, 0, NULL);
}
}
@@ -636,15 +672,13 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
dev->driver->atomic_commit(dev, state);
dev->driver->atomic_end(dev, state);
-
- drm_modeset_unlock_all(dev);
}
drm_framebuffer_unreference(fb);
}
EXPORT_SYMBOL(drm_framebuffer_remove);
-static DEFINE_WW_CLASS(crtc_ww_class);
+DEFINE_WW_CLASS(crtc_ww_class);
/**
* drm_crtc_init - Initialise a new CRTC object
@@ -660,26 +694,38 @@ static DEFINE_WW_CLASS(crtc_ww_class);
int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
const struct drm_crtc_funcs *funcs)
{
+ struct drm_mode_config *config = &dev->mode_config;
int ret;
+ if (!crtc->state)
+ crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+
crtc->dev = dev;
crtc->funcs = funcs;
- crtc->invert_dimensions = false;
+ crtc->state->invert_dimensions = false;
drm_modeset_lock_all(dev);
ww_mutex_init(&crtc->mutex, &crtc_ww_class);
mutex_lock_nest_lock(&crtc->mutex.base, &dev->mode_config.mutex);
+ INIT_LIST_HEAD(&crtc->lock_head);
+
ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
if (ret)
goto out;
crtc->base.properties = &crtc->properties;
- crtc->base.propvals = &crtc->propvals;
+ crtc->base.propvals = &crtc->state->propvals;
list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
dev->mode_config.num_crtc++;
+ drm_object_attach_property(&crtc->base, config->prop_mode, 0);
+ drm_object_attach_property(&crtc->base, config->prop_connector_ids, 0);
+ drm_object_attach_property(&crtc->base, config->prop_fb_id, 0);
+ drm_object_attach_property(&crtc->base, config->prop_src_x, 0);
+ drm_object_attach_property(&crtc->base, config->prop_src_y, 0);
+
out:
drm_modeset_unlock_all(dev);
@@ -702,12 +748,162 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
kfree(crtc->gamma_store);
crtc->gamma_store = NULL;
+ WARN_ON(!list_empty(&crtc->lock_head));
+
drm_mode_object_put(dev, &crtc->base);
list_del(&crtc->head);
dev->mode_config.num_crtc--;
}
EXPORT_SYMBOL(drm_crtc_cleanup);
+// XXX de-duplicate from drm_atomic_helper.c:
+// probably we want to stash the drm_display_mode as a ptr (transient data) on the state
+// so we only convert it once.. maybe in set_property()?
+static struct drm_display_mode *get_mode(struct drm_crtc *crtc, struct drm_crtc_state *cstate)
+{
+ struct drm_display_mode *mode = NULL;
+ if (cstate->mode_valid) {
+ struct drm_device *dev = crtc->dev;
+ int ret;
+
+ mode = drm_mode_create(dev);
+ if (!mode)
+ return ERR_PTR(-ENOMEM);
+
+ ret = drm_crtc_convert_umode(mode, &cstate->mode);
+ if (ret) {
+ DRM_DEBUG_KMS("Invalid mode\n");
+ drm_mode_destroy(dev, mode);
+ return ERR_PTR(ret);
+ }
+
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ }
+ return mode;
+}
+
+
+int drm_crtc_check_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct drm_framebuffer *fb = state->fb;
+ int hdisplay, vdisplay;
+ struct drm_display_mode *mode = get_mode(crtc, state);
+
+ if (IS_ERR(mode))
+ return PTR_ERR(mode);
+
+ /* disabling the crtc is allowed: */
+ if (!(fb && state->mode_valid))
+ return 0;
+
+ hdisplay = state->mode.hdisplay;
+ vdisplay = state->mode.vdisplay;
+
+ if (mode && drm_mode_is_stereo(mode)) {
+ struct drm_display_mode adjusted = *mode;
+
+ drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
+ hdisplay = adjusted.crtc_hdisplay;
+ vdisplay = adjusted.crtc_vdisplay;
+ }
+
+ if (state->invert_dimensions)
+ swap(hdisplay, vdisplay);
+
+ /* For some reason crtc x/y offsets are signed internally. */
+ if (state->x > INT_MAX || state->y > INT_MAX)
+ return -ERANGE;
+
+ if (hdisplay > fb->width ||
+ vdisplay > fb->height ||
+ state->x > fb->width - hdisplay ||
+ state->y > fb->height - vdisplay) {
+ DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
+ fb->width, fb->height, hdisplay, vdisplay,
+ state->x, state->y,
+ state->invert_dimensions ? " (inverted)" : "");
+ return -ENOSPC;
+ }
+
+ if (crtc->enabled && !state->set_config) {
+ if (crtc->state->fb->pixel_format != fb->pixel_format) {
+ DRM_DEBUG_KMS("Page flip is not allowed to "
+ "change frame buffer format.\n");
+ return -EINVAL;
+ }
+ }
+
+ if (state->num_connector_ids == 0) {
+ DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
+ return -EINVAL;
+ }
+
+ if (mode)
+ drm_mode_destroy(crtc->dev, mode);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_crtc_check_state);
+
+void drm_crtc_commit_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ crtc->state = state;
+ crtc->base.propvals = &state->propvals;
+}
+EXPORT_SYMBOL(drm_crtc_commit_state);
+
+int drm_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_crtc_state *state,
+ struct drm_property *property,
+ uint64_t value, void *blob_data)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ drm_object_property_set_value(&crtc->base,
+ &state->propvals, property, value, blob_data);
+
+ if (property == config->prop_mode) {
+ if (!blob_data) {
+ memset(&state->mode, 0, sizeof(state->mode));
+ state->mode_valid = false;
+ } else {
+ /* check size: */
+ if (value < sizeof(struct drm_mode_modeinfo))
+ return -EINVAL;
+ state->mode = *(struct drm_mode_modeinfo *)blob_data;
+ state->mode_valid = true;
+ }
+ state->set_config = true;
+ } else if (property == config->prop_connector_ids) {
+ state->num_connector_ids = value / sizeof(state->connector_ids[0]);
+ state->connector_ids = blob_data;
+ state->set_config = true;
+ } else if (property == config->prop_fb_id) {
+ state->new_fb = true;
+ state->fb = drm_framebuffer_lookup(dev, value);
+ } else if (property == config->prop_src_x) {
+ int x = *(int *)&value;
+ if (state->x != x) {
+ state->x = x;
+ state->set_config = true;
+ }
+ } else if (property == config->prop_src_y) {
+ int y = *(int *)&value;
+ if (state->y != y) {
+ state->y = y;
+ state->set_config = true;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_crtc_set_property);
+
/**
* drm_mode_probed_add - add a mode to a connector's probed mode list
* @connector: connector the new mode
@@ -1093,7 +1289,14 @@ int drm_plane_set_property(struct drm_plane *plane,
state->fb = drm_framebuffer_lookup(dev, value);
} else if (property == config->prop_crtc_id) {
struct drm_mode_object *obj = drm_property_get_obj(property, value);
- state->crtc = obj ? obj_to_crtc(obj) : NULL;
+ struct drm_crtc *crtc = obj ? obj_to_crtc(obj) : NULL;
+ /* take the lock of the incoming crtc as well, moving
+ * plane between crtcs is synchronized on both incoming
+ * and outgoing crtc.
+ */
+ if (crtc)
+ drm_modeset_lock_crtc(crtc, state->state);
+ state->crtc = crtc;
} else if (property == config->prop_crtc_x) {
state->crtc_x = U642I64(value);
} else if (property == config->prop_crtc_y) {
@@ -1269,6 +1472,16 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
return -ENOMEM;
dev->mode_config.prop_crtc_id = prop;
+ prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "CONNECTOR_IDS", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_connector_ids = prop;
+
+ prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "MODE", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_mode = prop;
+
return 0;
}
@@ -1533,7 +1746,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
* RETURNS:
* Zero on success, errno on failure.
*/
-static int drm_crtc_convert_umode(struct drm_display_mode *out,
+int drm_crtc_convert_umode(struct drm_display_mode *out,
const struct drm_mode_modeinfo *in)
{
if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
@@ -1782,11 +1995,11 @@ int drm_mode_getcrtc(struct drm_device *dev,
}
crtc = obj_to_crtc(obj);
- crtc_resp->x = crtc->x;
- crtc_resp->y = crtc->y;
+ crtc_resp->x = crtc->state->x;
+ crtc_resp->y = crtc->state->y;
crtc_resp->gamma_size = crtc->gamma_size;
- if (crtc->fb)
- crtc_resp->fb_id = crtc->fb->base.id;
+ if (crtc->state->fb)
+ crtc_resp->fb_id = crtc->state->fb->base.id;
else
crtc_resp->fb_id = 0;
@@ -2213,45 +2426,6 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
}
EXPORT_SYMBOL(drm_mode_set_config_internal);
-/*
- * Checks that the framebuffer is big enough for the CRTC viewport
- * (x, y, hdisplay, vdisplay)
- */
-static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
- int x, int y,
- const struct drm_display_mode *mode,
- const struct drm_framebuffer *fb)
-
-{
- int hdisplay, vdisplay;
-
- hdisplay = mode->hdisplay;
- vdisplay = mode->vdisplay;
-
- if (drm_mode_is_stereo(mode)) {
- struct drm_display_mode adjusted = *mode;
-
- drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
- hdisplay = adjusted.crtc_hdisplay;
- vdisplay = adjusted.crtc_vdisplay;
- }
-
- if (crtc->invert_dimensions)
- swap(hdisplay, vdisplay);
-
- if (hdisplay > fb->width ||
- vdisplay > fb->height ||
- x > fb->width - hdisplay ||
- y > fb->height - vdisplay) {
- DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
- fb->width, fb->height, hdisplay, vdisplay, x, y,
- crtc->invert_dimensions ? " (inverted)" : "");
- return -ENOSPC;
- }
-
- return 0;
-}
-
/**
* drm_mode_setcrtc - set CRTC configuration
* @dev: drm device for the ioctl
@@ -2272,22 +2446,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
struct drm_mode_crtc *crtc_req = data;
struct drm_mode_object *obj;
struct drm_crtc *crtc;
- struct drm_connector **connector_set = NULL, *connector;
- struct drm_framebuffer *fb = NULL;
- struct drm_display_mode *mode = NULL;
- struct drm_mode_set set;
- uint32_t __user *set_connectors_ptr;
+ uint32_t fb_id = -1;
+ uint32_t *connector_ids = NULL;
+ void *state = NULL;
int ret;
int i;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- /* For some reason crtc x/y offsets are signed internally. */
- if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
- return -ERANGE;
-
- drm_modeset_lock_all(dev);
obj = drm_mode_object_find(dev, crtc_req->crtc_id,
DRM_MODE_OBJECT_CRTC);
if (!obj) {
@@ -2307,55 +2474,15 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
ret = -EINVAL;
goto out;
}
- fb = crtc->fb;
- /* Make refcounting symmetric with the lookup path. */
- drm_framebuffer_reference(fb);
+ fb_id = crtc->base.id;
} else {
- fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
- if (!fb) {
- DRM_DEBUG_KMS("Unknown FB ID%d\n",
- crtc_req->fb_id);
- ret = -ENOENT;
- goto out;
- }
- }
-
- mode = drm_mode_create(dev);
- if (!mode) {
- ret = -ENOMEM;
- goto out;
+ fb_id = crtc_req->fb_id;
}
-
- ret = drm_crtc_convert_umode(mode, &crtc_req->mode);
- if (ret) {
- DRM_DEBUG_KMS("Invalid mode\n");
- goto out;
- }
-
- drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-
- ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
- mode, fb);
- if (ret)
- goto out;
-
- }
-
- if (crtc_req->count_connectors == 0 && mode) {
- DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
- ret = -EINVAL;
- goto out;
- }
-
- if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
- DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
- crtc_req->count_connectors);
- ret = -EINVAL;
- goto out;
}
if (crtc_req->count_connectors > 0) {
- u32 out_id;
+ uint32_t __user *set_connectors_ptr =
+ (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
/* Avoid unbounded kernel memory allocation */
if (crtc_req->count_connectors > config->num_connector) {
@@ -2363,54 +2490,52 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out;
}
- connector_set = kmalloc(crtc_req->count_connectors *
- sizeof(struct drm_connector *),
+ connector_ids = kmalloc(crtc_req->count_connectors *
+ sizeof(connector_ids[0]),
GFP_KERNEL);
- if (!connector_set) {
+ if (!connector_ids) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < crtc_req->count_connectors; i++) {
- set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
+ u32 out_id;
+
if (get_user(out_id, &set_connectors_ptr[i])) {
ret = -EFAULT;
goto out;
}
-
- obj = drm_mode_object_find(dev, out_id,
- DRM_MODE_OBJECT_CONNECTOR);
- if (!obj) {
- DRM_DEBUG_KMS("Connector id %d unknown\n",
- out_id);
- ret = -ENOENT;
- goto out;
- }
- connector = obj_to_connector(obj);
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
- connector->base.id,
- drm_get_connector_name(connector));
-
- connector_set[i] = connector;
+ connector_ids[i] = out_id;
}
}
- set.crtc = crtc;
- set.x = crtc_req->x;
- set.y = crtc_req->y;
- set.mode = mode;
- set.connectors = connector_set;
- set.num_connectors = crtc_req->count_connectors;
- set.fb = fb;
- ret = drm_mode_set_config_internal(&set);
+ state = dev->driver->atomic_begin(dev, 0);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
-out:
- if (fb)
- drm_framebuffer_unreference(fb);
+ ret =
+ drm_mode_set_obj_prop(obj, state,
+ config->prop_mode, sizeof(crtc_req->mode), &crtc_req->mode) ||
+ drm_mode_set_obj_prop(obj, state,
+ config->prop_connector_ids,
+ crtc_req->count_connectors * sizeof(connector_ids[0]),
+ connector_ids) ||
+ drm_mode_set_obj_prop(obj, state,
+ config->prop_fb_id, fb_id, NULL) ||
+ drm_mode_set_obj_prop(obj, state,
+ config->prop_src_x, crtc_req->x, NULL) ||
+ drm_mode_set_obj_prop(obj, state,
+ config->prop_src_y, crtc_req->y, NULL) ||
+ dev->driver->atomic_check(dev, state);
+ if (ret)
+ goto out;
- kfree(connector_set);
- drm_mode_destroy(dev, mode);
- drm_modeset_unlock_all(dev);
+ ret = dev->driver->atomic_commit(dev, state);
+
+out:
+ if (state)
+ dev->driver->atomic_end(dev, state);
+ kfree(connector_ids);
return ret;
}
@@ -2435,7 +2560,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
}
crtc = obj_to_crtc(obj);
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
if (req->flags & DRM_MODE_CURSOR_BO) {
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
ret = -ENXIO;
@@ -2459,7 +2584,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
}
}
out:
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
return ret;
@@ -3519,9 +3644,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc,
if (crtc->funcs->set_property)
ret = crtc->funcs->set_property(crtc, state, property,
value, blob_data);
- if (!ret)
- drm_object_property_set_value(&crtc->base, &crtc->propvals,
- property, value, NULL);
return ret;
}
@@ -3847,15 +3969,60 @@ out:
return ret;
}
+static struct drm_pending_vblank_event *create_vblank_event(
+ struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
+{
+ struct drm_pending_vblank_event *e = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (file_priv->event_space < sizeof e->event) {
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ goto out;
+ }
+ file_priv->event_space -= sizeof e->event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ e = kzalloc(sizeof *e, GFP_KERNEL);
+ if (e == NULL) {
+ spin_lock_irqsave(&dev->event_lock, flags);
+ file_priv->event_space += sizeof e->event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ goto out;
+ }
+
+ e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+ e->event.base.length = sizeof e->event;
+ e->event.user_data = user_data;
+ e->base.event = &e->event.base;
+ e->base.file_priv = file_priv;
+ e->base.destroy =
+ (void (*) (struct drm_pending_event *)) kfree;
+
+out:
+ return e;
+}
+
+static void destroy_vblank_event(struct drm_device *dev,
+ struct drm_file *file_priv, struct drm_pending_vblank_event *e)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ file_priv->event_space += sizeof e->event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ kfree(e);
+}
+
int drm_mode_page_flip_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_crtc_page_flip *page_flip = data;
+ struct drm_mode_config *config = &dev->mode_config;
struct drm_mode_object *obj;
struct drm_crtc *crtc;
- struct drm_framebuffer *fb = NULL, *old_fb = NULL;
struct drm_pending_vblank_event *e = NULL;
- unsigned long flags;
+ void *state;
int ret = -EINVAL;
if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -3870,92 +4037,37 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
return -ENOENT;
crtc = obj_to_crtc(obj);
- ww_mutex_lock(&crtc->mutex, NULL);
- if (crtc->fb == NULL) {
- /* The framebuffer is currently unbound, presumably
- * due to a hotplug event, that userspace has not
- * yet discovered.
- */
- ret = -EBUSY;
- goto out;
- }
-
- if (crtc->funcs->page_flip == NULL)
- goto out;
-
- fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
- if (!fb) {
- ret = -ENOENT;
- goto out;
- }
-
- ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
- if (ret)
- goto out;
-
- if (crtc->fb->pixel_format != fb->pixel_format) {
- DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
- ret = -EINVAL;
- goto out;
- }
+ state = dev->driver->atomic_begin(dev, page_flip->flags);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
- ret = -ENOMEM;
- spin_lock_irqsave(&dev->event_lock, flags);
- if (file_priv->event_space < sizeof e->event) {
- spin_unlock_irqrestore(&dev->event_lock, flags);
+ e = create_vblank_event(dev, file_priv, page_flip->user_data);
+ if (!e) {
+ ret = -ENOMEM;
goto out;
}
- file_priv->event_space -= sizeof e->event;
- spin_unlock_irqrestore(&dev->event_lock, flags);
-
- e = kzalloc(sizeof *e, GFP_KERNEL);
- if (e == NULL) {
- spin_lock_irqsave(&dev->event_lock, flags);
- file_priv->event_space += sizeof e->event;
- spin_unlock_irqrestore(&dev->event_lock, flags);
+ ret = dev->driver->atomic_set_event(dev, state, obj, e);
+ if (ret) {
goto out;
}
-
- e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
- e->event.base.length = sizeof e->event;
- e->event.user_data = page_flip->user_data;
- e->base.event = &e->event.base;
- e->base.file_priv = file_priv;
- e->base.destroy =
- (void (*) (struct drm_pending_event *)) kfree;
}
- old_fb = crtc->fb;
- ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
- if (ret) {
- if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
- spin_lock_irqsave(&dev->event_lock, flags);
- file_priv->event_space += sizeof e->event;
- spin_unlock_irqrestore(&dev->event_lock, flags);
- kfree(e);
- }
- /* Keep the old fb, don't unref it. */
- old_fb = NULL;
- } else {
- /*
- * Warn if the driver hasn't properly updated the crtc->fb
- * field to reflect that the new framebuffer is now used.
- * Failing to do so will screw with the reference counting
- * on framebuffers.
- */
- WARN_ON(crtc->fb != fb);
- /* Unref only the old framebuffer. */
- fb = NULL;
- }
+ ret = drm_mode_set_obj_prop(obj, state,
+ config->prop_fb_id, page_flip->fb_id, NULL);
+ if (ret)
+ goto out;
-out:
- if (fb)
- drm_framebuffer_unreference(fb);
- if (old_fb)
- drm_framebuffer_unreference(old_fb);
- ww_mutex_unlock(&crtc->mutex);
+ ret = dev->driver->atomic_check(dev, state);
+ if (ret)
+ goto out;
+ ret = dev->driver->atomic_commit(dev, state);
+
+out:
+ if (ret && e)
+ destroy_vblank_event(dev, file_priv, e);
+ dev->driver->atomic_end(dev, state);
return ret;
}
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 61b5a47..df3ad41 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -429,13 +429,8 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini);
*/
void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma)
{
- if (fbdev_cma) {
- struct drm_device *dev = fbdev_cma->fb_helper.dev;
-
- drm_modeset_lock_all(dev);
- drm_fb_helper_restore_fbdev_mode(&fbdev_cma->fb_helper);
- drm_modeset_unlock_all(dev);
- }
+ if (fbdev_cma)
+ drm_fb_helper_restore_fbdev_mode(&fbdev_cma->fb_helper, false);
}
EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 5773468..294fe5e 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -276,12 +276,15 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave);
/**
* drm_fb_helper_restore_fbdev_mode - restore fbdev configuration
* @fb_helper: fbcon to restore
+ * @lockless: true in drm_fb_helper_force_kernel_mode() path, to avoid
+ * blocking in panic case, everywhere else should use false
*
* This should be called from driver's drm ->lastclose callback
* when implementing an fbcon on top of kms using this helper. This ensures that
* the user isn't greeted with a black screen when e.g. X dies.
*/
-bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper,
+ bool lockless)
{
struct drm_device *dev = fb_helper->dev;
struct drm_plane *plane;
@@ -289,9 +292,8 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
void *state;
int i;
- drm_warn_on_modeset_not_all_locked(dev);
-
- state = dev->driver->atomic_begin(dev, 0);
+ state = dev->driver->atomic_begin(dev, lockless ?
+ DRM_MODE_ATOMIC_NOLOCK : 0);
if (IS_ERR(state)) {
DRM_ERROR("failed to restore fbdev mode\n");
return true;
@@ -343,7 +345,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF)
continue;
- ret = drm_fb_helper_restore_fbdev_mode(helper);
+ ret = drm_fb_helper_restore_fbdev_mode(helper, true);
if (ret)
error = true;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 4ae55b8..c1ef671 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -14,6 +14,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include "exynos_drm_crtc.h"
#include "exynos_drm_drv.h"
@@ -286,7 +287,9 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
return 0;
}
- return -EINVAL;
+ return drm_crtc_set_property(crtc,
+ drm_atomic_get_crtc_state(crtc, state),
+ property, val, blob_data);
}
static struct drm_crtc_funcs exynos_crtc_funcs = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index e7c2f2d..8032021 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -354,7 +354,5 @@ void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
if (!private || !private->fb_helper)
return;
- drm_modeset_lock_all(dev);
- drm_fb_helper_restore_fbdev_mode(private->fb_helper);
- drm_modeset_unlock_all(dev);
+ drm_fb_helper_restore_fbdev_mode(private->fb_helper, false);
}
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 8fbfa06..2b4bbf5 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -1022,6 +1022,7 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
.cursor_move = gma_crtc_cursor_move,
.gamma_set = gma_crtc_gamma_set,
.set_config = gma_crtc_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = gma_crtc_destroy,
};
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index 34c3116..a6545fe 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -153,11 +153,9 @@ static void psb_lastclose(struct drm_device *dev)
struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_fbdev *fbdev = dev_priv->fbdev;
- drm_modeset_lock_all(dev);
- ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper);
+ ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper, false);
if (ret)
DRM_DEBUG("failed to restore crtc mode\n");
- drm_modeset_unlock_all(dev);
return;
}
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index c8841ac..35e13ef 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -444,6 +444,7 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
.cursor_move = gma_crtc_cursor_move,
.gamma_set = gma_crtc_gamma_set,
.set_config = gma_crtc_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = gma_crtc_destroy,
};
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3b4e60e..02d705b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2232,11 +2232,11 @@ void intel_display_handle_reset(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
if (intel_crtc->active)
dev_priv->display.update_plane(crtc, crtc->fb,
crtc->x, crtc->y);
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
}
}
@@ -7550,7 +7550,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
if (encoder->crtc) {
crtc = encoder->crtc;
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
old->dpms_mode = connector->dpms;
old->load_detect_temp = false;
@@ -7581,7 +7581,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
return false;
}
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
intel_encoder->new_crtc = to_intel_crtc(crtc);
to_intel_connector(connector)->new_encoder = intel_encoder;
@@ -7609,7 +7609,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
if (IS_ERR(fb)) {
DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
return false;
}
@@ -7617,7 +7617,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
if (old->release_fb)
old->release_fb->funcs->destroy(old->release_fb);
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
return false;
}
@@ -7648,7 +7648,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
drm_framebuffer_unreference(old->release_fb);
}
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
return;
}
@@ -7656,7 +7656,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
if (old->dpms_mode != DRM_MODE_DPMS_ON)
connector->funcs->dpms(connector, old->dpms_mode);
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
}
static int i9xx_pll_refclk(struct drm_device *dev,
@@ -9778,6 +9778,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.cursor_move = intel_crtc_cursor_move,
.gamma_set = intel_crtc_gamma_set,
.set_config = intel_crtc_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = intel_crtc_destroy,
.page_flip = intel_crtc_page_flip,
};
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 895fcb4..4f7046d 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -313,11 +313,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
if (INTEL_INFO(dev)->num_pipes == 0)
return;
- drm_modeset_lock_all(dev);
-
- ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
+ ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper, false);
if (ret)
DRM_DEBUG("failed to restore crtc mode\n");
-
- drm_modeset_unlock_all(dev);
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index ee6ed63..8b796e1 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1296,6 +1296,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
.cursor_move = mga_crtc_cursor_move,
.gamma_set = mga_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = mga_crtc_destroy,
};
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
index 37a3fd2..ba6ed7d 100644
--- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
@@ -427,8 +427,9 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
static int mdp4_crtc_set_property(struct drm_crtc *crtc, void *state,
struct drm_property *property, uint64_t val, void *blob_data)
{
- // XXX
- return -EINVAL;
+ return drm_crtc_set_property(crtc,
+ drm_atomic_get_crtc_state(crtc, state),
+ property, val, blob_data);
}
#define CURSOR_WIDTH 64
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index dadd55a..cd7cd43 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -319,11 +319,8 @@ static void msm_preclose(struct drm_device *dev, struct drm_file *file)
static void msm_lastclose(struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
- if (priv->fbdev) {
- drm_modeset_lock_all(dev);
- drm_fb_helper_restore_fbdev_mode(priv->fbdev);
- drm_modeset_unlock_all(dev);
- }
+ if (priv->fbdev)
+ drm_fb_helper_restore_fbdev_mode(priv->fbdev, false);
}
static irqreturn_t msm_irq(DRM_IRQ_ARGS)
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 0e3270c..605fdb6 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -1086,6 +1086,7 @@ static const struct drm_crtc_funcs nv04_crtc_funcs = {
.cursor_move = nv04_crtc_cursor_move,
.gamma_set = nv_crtc_gamma_set,
.set_config = nouveau_crtc_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.page_flip = nouveau_crtc_page_flip,
.destroy = nv_crtc_destroy,
};
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index f8e66c0..bfcdf8e 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1327,6 +1327,7 @@ static const struct drm_crtc_funcs nv50_crtc_func = {
.cursor_move = nv50_crtc_cursor_move,
.gamma_set = nv50_crtc_gamma_set,
.set_config = nouveau_crtc_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = nv50_crtc_destroy,
.page_flip = nouveau_crtc_page_flip,
};
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index c040fc6..865e863 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -307,13 +307,13 @@ static void page_flip_worker(struct work_struct *work)
struct drm_display_mode *mode = &crtc->mode;
struct drm_gem_object *bo;
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
0, 0, mode->hdisplay, mode->vdisplay,
crtc->x << 16, crtc->y << 16,
mode->hdisplay << 16, mode->vdisplay << 16,
vblank_cb, crtc);
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
bo = omap_framebuffer_bo(crtc->fb, 0);
drm_gem_object_unreference_unlocked(bo);
@@ -367,14 +367,19 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, void *state,
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_drm_private *priv = crtc->dev->dev_private;
+ struct drm_crtc_state *cstate = drm_atomic_get_crtc_state(crtc, state);
+ int ret;
if (property == priv->rotation_prop) {
- crtc->invert_dimensions =
+ cstate->invert_dimensions =
!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
}
- return omap_plane_set_property(omap_crtc->plane, state,
+ ret = omap_plane_set_property(omap_crtc->plane, state,
property, val, blob_data);
+ if (ret)
+ ret = drm_crtc_set_property(crtc, cstate, property, val, blob_data);
+ return ret;
}
static const struct drm_crtc_funcs omap_crtc_funcs = {
@@ -447,7 +452,7 @@ static void apply_worker(struct work_struct *work)
* the callbacks and list modification all serialized
* with respect to modesetting ioctls from userspace.
*/
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
dispc_runtime_get();
/*
@@ -492,7 +497,7 @@ static void apply_worker(struct work_struct *work)
out:
dispc_runtime_put();
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
}
int omap_crtc_apply(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index e1e794a..cfd40f9 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -553,7 +553,7 @@ static void dev_lastclose(struct drm_device *dev)
*/
for (i = 0; i < priv->num_crtcs; i++) {
drm_object_property_set_value(&priv->crtcs[i]->base,
- &priv->crtcs[i]->propvals,
+ &priv->crtcs[i]->state->propvals,
priv->rotation_prop, 0, NULL);
}
@@ -564,9 +564,7 @@ static void dev_lastclose(struct drm_device *dev)
}
}
- drm_modeset_lock_all(dev);
- ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev);
- drm_modeset_unlock_all(dev);
+ ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev, false);
if (ret)
DBG("failed to restore crtc mode");
}
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index d36abbc..29b9572 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -29,6 +29,7 @@
#include "qxl_drv.h"
#include "qxl_object.h"
#include "drm_crtc_helper.h"
+#include "drm_atomic_helper.h"
static bool qxl_head_enabled(struct qxl_head *head)
{
@@ -373,6 +374,7 @@ static const struct drm_crtc_funcs qxl_crtc_funcs = {
.cursor_set2 = qxl_crtc_cursor_set2,
.cursor_move = qxl_crtc_cursor_move,
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = qxl_crtc_destroy,
};
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 7b25381..84e0c5e 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -32,6 +32,7 @@
#include <linux/pm_runtime.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_edid.h>
static void avivo_crtc_load_lut(struct drm_crtc *crtc)
@@ -544,6 +545,7 @@ static const struct drm_crtc_funcs radeon_crtc_funcs = {
.cursor_move = radeon_crtc_cursor_move,
.gamma_set = radeon_crtc_gamma_set,
.set_config = radeon_crtc_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = radeon_crtc_destroy,
.page_flip = radeon_crtc_page_flip,
};
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index a9d24e4..c840ba8 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -17,6 +17,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
@@ -528,6 +529,7 @@ static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
static const struct drm_crtc_funcs crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.page_flip = rcar_du_crtc_page_flip,
};
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 9e86b99..9209526 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -17,6 +17,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
@@ -496,6 +497,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
static const struct drm_crtc_funcs crtc_funcs = {
.destroy = drm_crtc_cleanup,
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.page_flip = shmob_drm_crtc_page_flip,
};
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index 490f771..59f7fd1 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -384,9 +384,6 @@ void tegra_drm_fb_exit(struct drm_device *drm)
void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
{
- if (fbdev) {
- drm_modeset_lock_all(fbdev->base.dev);
- drm_fb_helper_restore_fbdev_mode(&fbdev->base);
- drm_modeset_unlock_all(fbdev->base.dev);
- }
+ if (fbdev)
+ drm_fb_helper_restore_fbdev_mode(&fbdev->base, false);
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index d36efc1..34d9804 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -411,6 +411,7 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
.destroy = tilcdc_crtc_destroy,
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.page_flip = tilcdc_crtc_page_flip,
};
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 2ae1eb7..e05b2ea 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -14,6 +14,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
#include "udl_drv.h"
/*
@@ -383,6 +384,7 @@ static struct drm_crtc_helper_funcs udl_helper_funcs = {
static const struct drm_crtc_funcs udl_crtc_funcs = {
.set_config = drm_crtc_helper_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.destroy = udl_crtc_destroy,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 7b3bf18..36c9301 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -186,7 +186,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
* can do this since the caller in the drm core doesn't check anything
* which is protected by any looks.
*/
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
drm_modeset_lock_all(dev_priv->dev);
/* A lot of the code assumes this */
@@ -251,9 +251,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
ret = 0;
out:
drm_modeset_unlock_all(dev_priv->dev);
-// XXX umm, we probably need the state object here to properly
-// re-aquire the lock..
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
return ret;
}
@@ -274,7 +272,7 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
* can do this since the caller in the drm core doesn't check anything
* which is protected by any looks.
*/
- ww_mutex_unlock(&crtc->mutex);
+ drm_modeset_unlock_crtc(crtc);
drm_modeset_lock_all(dev_priv->dev);
vmw_cursor_update_position(dev_priv, shown,
@@ -282,9 +280,7 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
du->cursor_y + du->hotspot_y);
drm_modeset_unlock_all(dev_priv->dev);
-// XXX umm, we probably need the state object here to properly
-// re-aquire the lock..
- ww_mutex_lock(&crtc->mutex, NULL);
+ drm_modeset_lock_crtc(crtc, NULL);
return 0;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 79f7e8e..5d25f21 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -298,6 +298,7 @@ static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
.cursor_move = vmw_du_crtc_cursor_move,
.gamma_set = vmw_du_crtc_gamma_set,
.destroy = vmw_ldu_crtc_destroy,
+ .set_property = drm_atomic_helper_crtc_set_property,
.set_config = vmw_ldu_crtc_set_config,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index 26387c3..f65fec7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -394,6 +394,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
.gamma_set = vmw_du_crtc_gamma_set,
.destroy = vmw_sou_crtc_destroy,
.set_config = vmw_sou_crtc_set_config,
+ .set_property = drm_atomic_helper_crtc_set_property,
.page_flip = vmw_du_page_flip,
};
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index d0d29e1..44b51dd 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -65,6 +65,10 @@ struct drm_atomic_helper_funcs {
struct drm_plane_state *(*get_plane_state)(struct drm_plane *plane, void *state);
int (*check_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
int (*commit_plane_state)(struct drm_plane *plane, struct drm_plane_state *pstate);
+
+ struct drm_crtc_state *(*get_crtc_state)(struct drm_crtc *crtc, void *state);
+ int (*check_crtc_state)(struct drm_crtc *crtc, struct drm_crtc_state *cstate);
+ int (*commit_crtc_state)(struct drm_crtc *crtc, struct drm_crtc_state *cstate);
};
const extern struct drm_atomic_helper_funcs drm_atomic_helper_funcs;
@@ -108,6 +112,37 @@ drm_atomic_commit_plane_state(struct drm_plane *plane,
return funcs->commit_plane_state(plane, pstate);
}
+int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, void *state,
+ struct drm_property *property, uint64_t val, void *blob_data);
+void drm_atomic_helper_init_crtc_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *cstate, void *state);
+
+static inline struct drm_crtc_state *
+drm_atomic_get_crtc_state(struct drm_crtc *crtc, void *state)
+{
+ const struct drm_atomic_helper_funcs *funcs =
+ crtc->dev->driver->atomic_helpers;
+ return funcs->get_crtc_state(crtc, state);
+}
+
+static inline int
+drm_atomic_check_crtc_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *cstate)
+{
+ const struct drm_atomic_helper_funcs *funcs =
+ crtc->dev->driver->atomic_helpers;
+ return funcs->check_crtc_state(crtc, cstate);
+}
+
+static inline int
+drm_atomic_commit_crtc_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *cstate)
+{
+ const struct drm_atomic_helper_funcs *funcs =
+ crtc->dev->driver->atomic_helpers;
+ return funcs->commit_crtc_state(crtc, cstate);
+}
+
/**
* struct drm_atomic_helper_state - the state object used by atomic helpers
*/
@@ -117,6 +152,12 @@ struct drm_atomic_helper_state {
uint32_t flags;
struct drm_plane **planes;
struct drm_plane_state **pstates;
+ struct drm_crtc **crtcs;
+ struct drm_crtc_state **cstates;
+
+ struct ww_acquire_ctx ww_ctx;
+ struct list_head locked_crtcs;
+ bool locks_dropped;
};
static inline void
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index dfe8d20..2531658 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -333,6 +333,8 @@ struct drm_pending_vblank_event;
struct drm_plane;
struct drm_bridge;
+extern struct ww_class crtc_ww_class;
+
/**
* drm_crtc_funcs - control CRTCs for a given device
* @save: save CRTC state
@@ -399,18 +401,51 @@ struct drm_crtc_funcs {
};
/**
+ * drm_crtc_state - mutable crtc state
+ * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
+ * invert the width/height of the crtc. This is used if the driver
+ * is performing 90 or 270 degree rotated scanout
+ * @set_config: needs modeset (crtc->set_config())
+ * @new_fb: has the fb been changed
+ * @mode_valid: a valid mode has been set
+ * @num_connector_ids: the number of connector-ids
+ * @connector_ids: array of connector ids
+ * @mode: current mode timings
+ * @fb: the framebuffer that the CRTC is currently bound to
+ * @x: x position on screen
+ * @y: y position on screen
+ * @event: pending pageflip event
+ * @propvals: property values
+ * @state: current global/toplevel state object (for atomic) while an
+ * update is in progress, NULL otherwise.
+ */
+struct drm_crtc_state {
+ bool invert_dimensions : 1;
+ bool set_config : 1;
+ bool new_fb : 1;
+ bool mode_valid : 1; /* drop this if when mode a refcnt'd ptr */
+ uint8_t num_connector_ids;
+ uint32_t *connector_ids;
+ struct drm_mode_modeinfo mode;
+ struct drm_framebuffer *fb;
+ int x, y;
+
+ struct drm_pending_vblank_event *event;
+
+ struct drm_object_property_values propvals;
+
+ void *state;
+};
+
+/**
* drm_crtc - central CRTC control structure
* @dev: parent DRM device
* @head: list management
+ * @id: CRTC number, 0..n
* @base: base KMS object for ID tracking etc.
+ * @state: the mutable state
* @enabled: is this CRTC enabled?
- * @mode: current mode timings
* @hwmode: mode timings as programmed to hw regs
- * @invert_dimensions: for purposes of error checking crtc vs fb sizes,
- * invert the width/height of the crtc. This is used if the driver
- * is performing 90 or 270 degree rotated scanout
- * @x: x position on screen
- * @y: y position on screen
* @funcs: CRTC control functions
* @gamma_size: size of gamma ramp
* @gamma_store: gamma ramp values
@@ -427,6 +462,8 @@ struct drm_crtc {
struct drm_device *dev;
struct list_head head;
+ int id;
+
/**
* crtc mutex
*
@@ -436,10 +473,15 @@ struct drm_crtc {
*/
struct ww_mutex mutex;
+ /**
+ * CRTC's that are locked as part of an atomic update are added to
+ * a list (so we know what to unlock at the end).
+ */
+ struct list_head lock_head;
+
struct drm_mode_object base;
- /* framebuffer the connector is currently bound to */
- struct drm_framebuffer *fb;
+ struct drm_crtc_state *state;
/* Temporary tracking of the old fb while a modeset is ongoing. Used
* by drm_mode_set_config_internal to implement correct refcounting. */
@@ -447,17 +489,11 @@ struct drm_crtc {
bool enabled;
- /* Requested mode from modesetting. */
- struct drm_display_mode mode;
-
/* Programmed mode in hw, after adjustments for encoders,
* crtc, panel scaling etc. Needed for timestamping etc.
*/
struct drm_display_mode hwmode;
- bool invert_dimensions;
-
- int x, y;
const struct drm_crtc_funcs *funcs;
/* CRTC gamma size for reporting to userspace */
@@ -471,7 +507,15 @@ struct drm_crtc {
void *helper_private;
struct drm_object_properties properties;
- struct drm_object_property_values propvals;
+
+ /* These are (temporary) duplicate information from what is in the
+ * drm_crtc_state struct.. keeping duplicate copy here makes the
+ * switch to atomic far less intrusive. Once all the drivers and
+ * the crtc/fb helpers are updated, then we can remove these:
+ */
+ struct drm_framebuffer *fb;
+ int x, y;
+ struct drm_display_mode mode;
};
@@ -951,6 +995,8 @@ struct drm_mode_config {
struct drm_property *prop_crtc_h;
struct drm_property *prop_fb_id;
struct drm_property *prop_crtc_id;
+ struct drm_property *prop_connector_ids;
+ struct drm_property *prop_mode;
struct drm_property *edid_property;
struct drm_property *dpms_property;
@@ -998,6 +1044,8 @@ struct drm_prop_enum_list {
char *name;
};
+int drm_modeset_lock_crtc(struct drm_crtc *crtc, void *state);
+void drm_modeset_unlock_crtc(struct drm_crtc *crtc);
extern void drm_modeset_lock_all(struct drm_device *dev);
extern void drm_modeset_unlock_all(struct drm_device *dev);
extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
@@ -1006,6 +1054,14 @@ extern int drm_crtc_init(struct drm_device *dev,
struct drm_crtc *crtc,
const struct drm_crtc_funcs *funcs);
extern void drm_crtc_cleanup(struct drm_crtc *crtc);
+extern int drm_crtc_check_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state);
+extern void drm_crtc_commit_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state);
+extern int drm_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_crtc_state *state,
+ struct drm_property *property,
+ uint64_t value, void *blob_data);
extern void drm_connector_ida_init(void);
extern void drm_connector_ida_destroy(void);
@@ -1055,6 +1111,7 @@ extern const char *drm_get_tv_subconnector_name(int val);
extern const char *drm_get_tv_select_name(int val);
extern void drm_fb_release(struct drm_file *file_priv);
extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
+extern int drm_crtc_convert_umode(struct drm_display_mode *out, const struct drm_mode_modeinfo *in);
extern bool drm_probe_ddc(struct i2c_adapter *adapter);
extern struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 471f276..b130a4d 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -108,7 +108,8 @@ int drm_fb_helper_set_par(struct fb_info *info);
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);
-bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper);
+bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper,
+ bool lockless);
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
uint32_t fb_width, uint32_t fb_height);
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 9fed70e..a913953 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -508,4 +508,6 @@ struct drm_mode_destroy_dumb {
uint32_t handle;
};
+#define DRM_MODE_ATOMIC_NOLOCK 0x8000 /* only used internally */
+
#endif
--
1.8.4.2
next prev parent reply other threads:[~2013-11-20 20:48 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-20 20:47 [RFCv3 00/14] Atomic/nuclear modeset/pageflip Rob Clark
2013-11-20 20:48 ` [RFCv3 01/14] drm: add atomic fxns Rob Clark
2013-11-20 20:48 ` [RFCv3 02/14] drm: convert crtc to ww_mutex Rob Clark
2013-11-21 14:11 ` Maarten Lankhorst
2013-11-21 15:12 ` Rob Clark
2013-11-20 20:48 ` [RFCv3 03/14] drm: add object property type Rob Clark
2013-11-20 20:48 ` [RFCv3 04/14] drm: add DRM_MODE_PROP_DYNAMIC property flag Rob Clark
2013-11-20 20:48 ` [RFCv3 05/14] drm: add DRM_MODE_PROP_SIGNED " Rob Clark
2013-11-20 20:48 ` [RFCv3 06/14] drm: helpers to find mode objects Rob Clark
2013-11-20 20:48 ` [RFCv3 07/14] drm: split propvals out and blob property support Rob Clark
2013-11-20 20:48 ` [RFCv3 08/14] drm: Allow drm_mode_object_find() to look up an object of any type Rob Clark
2013-11-20 20:48 ` [RFCv3 09/14] drm: Refactor object property check code Rob Clark
2013-11-20 20:48 ` [RFCv3 10/14] drm: convert plane to properties/state Rob Clark
2013-11-20 20:48 ` Rob Clark [this message]
2013-11-21 14:25 ` [RFCv3 11/14] drm: convert crtc " Maarten Lankhorst
2013-11-20 20:48 ` [RFCv3 12/14] drm: Atomic modeset ioctl Rob Clark
2013-11-22 8:35 ` Inki Dae
2013-11-22 12:34 ` Rob Clark
2013-11-20 20:48 ` [RFCv3 13/14] drm/msm: add atomic support Rob Clark
2013-11-20 20:48 ` [RFCv3 14/14] HACK: drm: allow FB's in drm_mode_object_find Rob Clark
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1384980493-25499-12-git-send-email-robdclark@gmail.com \
--to=robdclark@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.