[RFCv4 10/14] drm: convert crtc to properties/state

2014-03-04 Thread Sean Paul
On Tue, Mar 4, 2014 at 5:04 PM, Rob Clark  wrote:
> On Tue, Mar 4, 2014 at 4:29 PM, Sean Paul  wrote:
>> On Mon, Nov 25, 2013 at 9:47 AM, Rob Clark  wrote:
>>> 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.
>>> ---
>
> 
>
>>> +static int check_connectors(struct drm_crtc *crtc, void *state, bool fix,
>>> +   uint32_t *connector_ids, uint32_t num_connector_ids)
>>> +{
>>> +   struct drm_mode_config *config = >dev->mode_config;
>>> +   struct drm_crtc *ocrtc; /* other connector */
>>> +
>>> +   list_for_each_entry(ocrtc, >crtc_list, head) {
>>> +   struct drm_crtc_state *ostate; /* other state */
>>> +   unsigned i;
>>> +
>>> +   if (ocrtc == crtc)
>>> +   continue;
>>> +
>>> +   ostate = drm_atomic_get_crtc_state(crtc, state);
>>
>> Hi Rob,
>> This will populate state's placeholder for ocrtc, which will have the
>> unintended consequence of committing ocrtc's state and thus
>> unreferencing ocrtc's current fb in
>> drm_atomic_helper_commit_crtc_state.
>>
>> Maybe a new transient state bit in drm_crtc_state which avoids the
>> commit_crtc_state call is in order?
>
> probably not a bad idea to avoid unnecessary commit,  but need to
> check if that is just masking a refcnt'ing problem.  Ie. userspace
> *should* be allowed to set properties on the crtc (for example, set
> color correction properties, etc) without causing an unintended
> finalizing of the fb..
>

Right, agreed.

Whenever I do a setcrtc on crtc A, I lose a reference to crtc B's
current fb (and vice versa). If I short-circuit this code, we don't
populate crtc B's cstate in state and the fb is not unreferenced. The
alternative would be to take a reference on crtc B's fb here, but that
will cause problems if crtc B is meant to be involved in the commit.

I pasted what I have locally below, everything seems well-behaved now:

diff --git a/drivers/gpu/drm/drm_atomic_helper.c
b/drivers/gpu/drm/drm_atomic_helper.c
index 2386ab1..9fe1276 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -485,6 +485,7 @@ void drm_atomic_helper_init_crtc_state(struct
drm_crtc *crtc,
/* this should never happen.. but make sure! */
WARN_ON(cstate->event);
cstate->event = NULL;
+   cstate->commit_state = false;
 }
 EXPORT_SYMBOL(drm_atomic_helper_init_crtc_state);

@@ -631,6 +632,9 @@ drm_atomic_helper_commit_crtc_state(struct drm_crtc *crtc,
struct drm_atomic_helper_state *a = cstate->state;
int ret = -EINVAL;

+   if (!cstate->commit_state)
+   return 0;
+
if (cstate->set_config)
return set_config(crtc, cstate);

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 4834dd7..49eda31 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -959,6 +959,7 @@ int drm_crtc_set_property(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct drm_mode_config *config = >mode_config;

+   state->commit_state = true;
drm_object_property_set_value(>base,
>propvals, property, value, blob_data);

diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b81a64c..043ca1e 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -482,6 +482,7 @@ struct drm_crtc_state {
bool set_config: 1;
bool new_fb: 1;
bool connectors_change : 1;
+   bool commit_state  : 1;

uint8_t num_connector_ids;
uint32_t *connector_ids;



> 
>
>>> @@ -3946,92 +4163,41 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>>> if (!crtc)
>>> return -ENOENT;
>>>
>>> -   drm_modeset_lock(>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, >mode, 
>>> fb);
>>> -   if (ret)
>>> -   goto out;
>>> -
>>> -   if (crtc->fb->pixel_format != 

[RFCv4 10/14] drm: convert crtc to properties/state

2014-03-04 Thread Rob Clark
On Tue, Mar 4, 2014 at 4:29 PM, Sean Paul  wrote:
> On Mon, Nov 25, 2013 at 9:47 AM, Rob Clark  wrote:
>> 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.
>> ---



>> +static int check_connectors(struct drm_crtc *crtc, void *state, bool fix,
>> +   uint32_t *connector_ids, uint32_t num_connector_ids)
>> +{
>> +   struct drm_mode_config *config = >dev->mode_config;
>> +   struct drm_crtc *ocrtc; /* other connector */
>> +
>> +   list_for_each_entry(ocrtc, >crtc_list, head) {
>> +   struct drm_crtc_state *ostate; /* other state */
>> +   unsigned i;
>> +
>> +   if (ocrtc == crtc)
>> +   continue;
>> +
>> +   ostate = drm_atomic_get_crtc_state(crtc, state);
>
> Hi Rob,
> This will populate state's placeholder for ocrtc, which will have the
> unintended consequence of committing ocrtc's state and thus
> unreferencing ocrtc's current fb in
> drm_atomic_helper_commit_crtc_state.
>
> Maybe a new transient state bit in drm_crtc_state which avoids the
> commit_crtc_state call is in order?

probably not a bad idea to avoid unnecessary commit,  but need to
check if that is just masking a refcnt'ing problem.  Ie. userspace
*should* be allowed to set properties on the crtc (for example, set
color correction properties, etc) without causing an unintended
finalizing of the fb..



>> @@ -3946,92 +4163,41 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>> if (!crtc)
>> return -ENOENT;
>>
>> -   drm_modeset_lock(>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, >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;
>> -   }
>> +retry:
>> +   state = dev->driver->atomic_begin(dev,
>> +   page_flip->flags | DRM_MODE_ATOMIC_NONBLOCK);
>> +   if (IS_ERR(state))
>> +   return PTR_ERR(state);
>>
>> if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
>> -   ret = -ENOMEM;
>> -   spin_lock_irqsave(>event_lock, flags);
>> -   if (file_priv->event_space < sizeof e->event) {
>> -   spin_unlock_irqrestore(>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(>event_lock, flags);
>> -
>> -   e = kzalloc(sizeof *e, GFP_KERNEL);
>> -   if (e == NULL) {
>> -   spin_lock_irqsave(>event_lock, flags);
>> -   file_priv->event_space += sizeof e->event;
>> -   spin_unlock_irqrestore(>event_lock, flags);
>> +   ret = dev->driver->atomic_set_event(dev, state, >base, 
>> 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 = >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(>event_lock, flags);
>> -   file_priv->event_space += sizeof e->event;
>> - 

[RFCv4 10/14] drm: convert crtc to properties/state

2014-03-04 Thread Sean Paul
On Mon, Nov 25, 2013 at 9:47 AM, Rob Clark  wrote:
> 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.
> ---



> +
> +static int remove_connector(struct drm_crtc *ocrtc,
> +   struct drm_crtc_state *ostate, void *state, int idx)
> +{
> +   struct drm_mode_config *config = >dev->mode_config;
> +   uint32_t *new_connector_ids;
> +   int a, b;
> +
> +   /* before deletion point: */
> +   a = idx * sizeof(ostate->connector_ids[0]);
> +
> +   /* after deletion point: */
> +   b = (ostate->num_connector_ids - 1 - idx) *
> +   sizeof(ostate->connector_ids[0]);
> +
> +   new_connector_ids = kmalloc(a+b, GFP_KERNEL);
> +   if (!new_connector_ids)
> +   return -ENOMEM;
> +
> +   memcpy(new_connector_ids, ostate->connector_ids, a);
> +   memcpy(_connector_ids[idx],
> +   >connector_ids[idx + 1], b);
> +
> +   return drm_mode_crtc_set_obj_prop(ocrtc, state,
> +   config->prop_connector_ids, a + b,
> +   new_connector_ids);
> +}
> +
> +static int check_connectors(struct drm_crtc *crtc, void *state, bool fix,
> +   uint32_t *connector_ids, uint32_t num_connector_ids)
> +{
> +   struct drm_mode_config *config = >dev->mode_config;
> +   struct drm_crtc *ocrtc; /* other connector */
> +
> +   list_for_each_entry(ocrtc, >crtc_list, head) {
> +   struct drm_crtc_state *ostate; /* other state */
> +   unsigned i;
> +
> +   if (ocrtc == crtc)
> +   continue;
> +
> +   ostate = drm_atomic_get_crtc_state(crtc, state);

Hi Rob,
This will populate state's placeholder for ocrtc, which will have the
unintended consequence of committing ocrtc's state and thus
unreferencing ocrtc's current fb in
drm_atomic_helper_commit_crtc_state.

Maybe a new transient state bit in drm_crtc_state which avoids the
commit_crtc_state call is in order?

> +   if (IS_ERR(ostate))
> +   return PTR_ERR(ostate);
> +
> +   for (i = 0; i < num_connector_ids; i++) {
> +   struct drm_connector *connector;
> +   uint32_t cid = connector_ids[i];
> +   int idx;
> +
> +retry:
> +   idx = connector_idx(ostate, cid);
> +   if (idx < 0)
> +   continue;
> +
> +   if (fix) {
> +   int ret = remove_connector(ocrtc,
> +   ostate, state, idx);
> +   if (ret)
> +   return ret;
> +   goto retry;
> +   }
> +
> +   connector = drm_connector_find(crtc->dev, cid);
> +   DRM_DEBUG_KMS("[CONNECTOR:%d:%s] already in use\n",
> +   connector->base.id,
> +   drm_get_connector_name(connector));
> +   return -EINVAL;
> +   }
> +   }
> +
> +   return 0;
> +}
> +
> +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(, 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",
> + 

[RFCv4 10/14] drm: convert crtc to properties/state

2013-12-11 Thread Rob Clark
On Wed, Dec 11, 2013 at 4:48 PM, Matt Roper  
wrote:
> On Mon, Nov 25, 2013 at 09:47:34AM -0500, Rob Clark wrote:
> ...
>> +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;
>> + int ret;
>> +
>> + ret = drm_modeset_lock(>mutex, state);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> + cstate = a->cstates[crtc->id];
>
> The id field of struct drm_crtc never seems to be initialized in the
> current DRM codebase, so this will always wind up looking up cstates[0];
> we probably want to initialize crtc->id in drm_crtc_init() at the same
> place we increment dev->mode_config.num_crtc.
>

yeah, it is supposed to be initialized in drm_crtc_init()..  I was
juggling the patches around a bit, possibly I screwed up and that
ended up in one of the later patches?

I'll go back and check this

> ...
>> +static int check_connectors(struct drm_crtc *crtc, void *state, bool fix,
>> + uint32_t *connector_ids, uint32_t num_connector_ids)
>> +{
>> + struct drm_mode_config *config = >dev->mode_config;
>> + struct drm_crtc *ocrtc; /* other connector */
>> +
>> + list_for_each_entry(ocrtc, >crtc_list, head) {
>> + struct drm_crtc_state *ostate; /* other state */
>> + unsigned i;
>> +
>> + if (ocrtc == crtc)
>> + continue;
>> +
>> + ostate = drm_atomic_get_crtc_state(crtc, state);
>
> I think you meant to use ocrtc here rather than crtc, right?
>

yes, good catch.  I need a driver with more than one connector to test
with, apparently ;-)

>
> I think you might also want to move patch 11 up above 9 & 10, otherwise
> you'll run into the lastclose deadlock while bisecting through this
> patchset.
>

good point.. that should be pretty easy to re-order

BR,
-R


>
> Matt
>
> --
> Matt Roper
> Intel Corporation


[RFCv4 10/14] drm: convert crtc to properties/state

2013-12-11 Thread Matt Roper
On Mon, Nov 25, 2013 at 09:47:34AM -0500, Rob Clark wrote:
...
> +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;
> + int ret;
> +
> + ret = drm_modeset_lock(>mutex, state);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + cstate = a->cstates[crtc->id];

The id field of struct drm_crtc never seems to be initialized in the
current DRM codebase, so this will always wind up looking up cstates[0];
we probably want to initialize crtc->id in drm_crtc_init() at the same
place we increment dev->mode_config.num_crtc.

...
> +static int check_connectors(struct drm_crtc *crtc, void *state, bool fix,
> + uint32_t *connector_ids, uint32_t num_connector_ids)
> +{
> + struct drm_mode_config *config = >dev->mode_config;
> + struct drm_crtc *ocrtc; /* other connector */
> +
> + list_for_each_entry(ocrtc, >crtc_list, head) {
> + struct drm_crtc_state *ostate; /* other state */
> + unsigned i;
> +
> + if (ocrtc == crtc)
> + continue;
> +
> + ostate = drm_atomic_get_crtc_state(crtc, state);

I think you meant to use ocrtc here rather than crtc, right?


I think you might also want to move patch 11 up above 9 & 10, otherwise
you'll run into the lastclose deadlock while bisecting through this
patchset.


Matt

-- 
Matt Roper
Intel Corporation


[RFCv4 10/14] drm: convert crtc to properties/state

2013-11-25 Thread Rob Clark
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.
---
 drivers/gpu/drm/ast/ast_mode.c |   1 +
 drivers/gpu/drm/cirrus/cirrus_mode.c   |   1 +
 drivers/gpu/drm/drm_atomic_helper.c| 277 -
 drivers/gpu/drm/drm_crtc.c | 622 ++---
 drivers/gpu/drm/exynos/exynos_drm_crtc.c   |   7 +-
 drivers/gpu/drm/gma500/cdv_intel_display.c |   1 +
 drivers/gpu/drm/gma500/psb_intel_display.c |   1 +
 drivers/gpu/drm/i915/intel_display.c   |   1 +
 drivers/gpu/drm/mgag200/mgag200_mode.c |   1 +
 drivers/gpu/drm/msm/mdp4/mdp4_crtc.c   |   6 +-
 drivers/gpu/drm/nouveau/dispnv04/crtc.c|   1 +
 drivers/gpu/drm/nouveau/nv50_display.c |   1 +
 drivers/gpu/drm/omapdrm/omap_crtc.c|  12 +-
 drivers/gpu/drm/omapdrm/omap_drv.c |   2 +-
 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/tilcdc/tilcdc_crtc.c   |   1 +
 drivers/gpu/drm/udl/udl_modeset.c  |   2 +
 drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c|   1 +
 drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c   |   1 +
 include/drm/drm_atomic_helper.h|  39 ++
 include/drm/drm_crtc.h |  82 +++-
 24 files changed, 818 insertions(+), 250 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 14e0571..9b60536 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -40,11 +40,13 @@ 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);

@@ -65,6 +67,12 @@ void *drm_atomic_helper_begin(struct drm_device *dev, 
uint32_t flags)
state->pstates = ptr;
ptr = >pstates[nplanes];

+   state->crtcs = ptr;
+   ptr = >crtcs[ncrtcs];
+
+   state->cstates = ptr;
+   ptr = >cstates[ncrtcs];
+
return state;
 }
 EXPORT_SYMBOL(drm_atomic_helper_begin);
@@ -83,7 +91,18 @@ 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);
+   if (IS_ERR(cstate))
+   return PTR_ERR(cstate);
+   cstate->event = event;
+   return 0;
+   }
+   default:
+   return -EINVAL;
+   }
 }
 EXPORT_SYMBOL(drm_atomic_helper_set_event);

@@ -102,6 +121,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++) {
@@ -112,6 +132,14 @@ int drm_atomic_helper_check(struct drm_device *dev, void 
*state)