]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'topic/atomic-core-2015-01-05' of git://anongit.freedesktop.org/drm-intel...
authorDave Airlie <airlied@redhat.com>
Thu, 8 Jan 2015 23:22:40 +0000 (09:22 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 8 Jan 2015 23:22:40 +0000 (09:22 +1000)
Next batch of atomic work. Most important is the propertification from Rob
and the nth iteration of the actual atomic ioctl originally from Ville.
Big differences compared to earlier revisions:
- Core properties are now fully handled by the core, drivers can only
  handle driver-specific properties.
- Atomic props&ioctl are opt-in per file_priv, userspace needs to
  explicitly ask for it (like universal plane support).
- For now all hidden behind the atomic module option until this has
  settled a bit.
- Atomic modesets are currently not possible since the exact abi for how
  to handle the mode property is still under discussion.

Besides this some cleanup patches from me and the addition of per-object
state to global state backpointers to simplify drivers.

* tag 'topic/atomic-core-2015-01-05' of git://anongit.freedesktop.org/drm-intel:
  drm: Ensure universal_planes is set for atomic
  drm/atomic: Hide drm.ko internal interfaces
  drm: Atomic modeset ioctl
  drm/atomic: atomic connector properties
  drm/atomic: atomic plane properties
  drm: small property creation cleanup
  drm/atomic: atomic_check functions
  drm: add atomic properties
  drm: refactor getproperties/getconnector
  drm: tweak getconnector locking
  drm: add atomic_get_property
  drm: add atomic_set_property wrappers
  drm: get rid of direct property value access
  drm: store property instead of id in obj attachment
  drm: allow property validation for refcnted props
  drm/atomic: Introduce state->obj backpointers
  drm/atomic-helper: Again check modeset *before* plane states
  drm/atomic-helper: Export both plane and modeset check helpers

1  2 
Documentation/DocBook/drm.tmpl
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
include/drm/drmP.h
include/drm/drm_crtc.h

index 8a0b2a84f4bf76404c6f4ae2f81f52c6b392afbd,2f4a299064251f88f0465a6e85fe3cbdc63125f6..640c2a30563f83a9be4767e6370bd3a0e044123f
                Driver supports dedicated render nodes.
              </para></listitem>
            </varlistentry>
+           <varlistentry>
+             <term>DRIVER_ATOMIC</term>
+             <listitem><para>
+               Driver supports atomic properties.  In this case the driver
+               must implement appropriate obj->atomic_get_property() vfuncs
+               for any modeset objects with driver specific properties.
+             </para></listitem>
+           </varlistentry>
          </variablelist>
        </sect3>
        <sect3>
@@@ -1377,7 -1385,7 +1385,7 @@@ int max_width, max_height;</synopsis
        <itemizedlist>
          <listitem>
          DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC.  Primary
 -        planes are the planes operated upon by by CRTC modesetting and flipping
 +        planes are the planes operated upon by CRTC modesetting and flipping
          operations described in <xref linkend="drm-kms-crtcops"/>.
          </listitem>
          <listitem>
@@@ -2362,7 -2370,6 +2370,7 @@@ void intel_crt_init(struct drm_device *
      </sect2>
      <sect2>
        <title>Modeset Helper Functions Reference</title>
 +!Iinclude/drm/drm_crtc_helper.h
  !Edrivers/gpu/drm/drm_crtc_helper.c
  !Pdrivers/gpu/drm/drm_crtc_helper.c overview
      </sect2>
        <td valign="top" >Description/Restrictions</td>
        </tr>
        <tr>
-       <td rowspan="25" valign="top" >DRM</td>
-       <td rowspan="4" valign="top" >Generic</td>
+       <td rowspan="36" valign="top" >DRM</td>
+       <td rowspan="5" valign="top" >Connector</td>
        <td valign="top" >“EDID”</td>
        <td valign="top" >BLOB | IMMUTABLE</td>
        <td valign="top" >0</td>
        <td valign="top" >Contains tiling information for a connector.</td>
        </tr>
        <tr>
-       <td rowspan="1" valign="top" >Plane</td>
+       <td valign="top" >“CRTC_ID”</td>
+       <td valign="top" >OBJECT</td>
+       <td valign="top" >DRM_MODE_OBJECT_CRTC</td>
+       <td valign="top" >Connector</td>
+       <td valign="top" >CRTC that connector is attached to (atomic)</td>
+       </tr>
+       <tr>
+       <td rowspan="11" valign="top" >Plane</td>
        <td valign="top" >“type”</td>
        <td valign="top" >ENUM | IMMUTABLE</td>
        <td valign="top" >{ "Overlay", "Primary", "Cursor" }</td>
        <td valign="top" >Plane type</td>
        </tr>
        <tr>
+       <td valign="top" >“SRC_X”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source x coordinate in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“SRC_Y”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source y coordinate in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“SRC_W”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source width in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“SRC_H”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout source height in 16.16 fixed point (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_X”</td>
+       <td valign="top" >SIGNED_RANGE</td>
+       <td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) x coordinate (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_Y”</td>
+       <td valign="top" >SIGNED_RANGE</td>
+       <td valign="top" >Min=INT_MIN, Max=INT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) y coordinate (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_W”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) width (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_H”</td>
+       <td valign="top" >RANGE</td>
+       <td valign="top" >Min=0, Max=UINT_MAX</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout CRTC (destination) height (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“FB_ID”</td>
+       <td valign="top" >OBJECT</td>
+       <td valign="top" >DRM_MODE_OBJECT_FB</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >Scanout framebuffer (atomic)</td>
+       </tr>
+       <tr>
+       <td valign="top" >“CRTC_ID”</td>
+       <td valign="top" >OBJECT</td>
+       <td valign="top" >DRM_MODE_OBJECT_CRTC</td>
+       <td valign="top" >Plane</td>
+       <td valign="top" >CRTC that plane is attached to (atomic)</td>
+       </tr>
+       <tr>
        <td rowspan="2" valign="top" >DVI-I</td>
        <td valign="top" >“subconnector”</td>
        <td valign="top" >ENUM</td>
index 2892d746a1e9552672a4eab5d37eb453aefc945e,20596423d52d159c7f49c981e419a6c15bb2f543..7e4acad3f6f9f132f40c3ea76d54e5048105461e
@@@ -38,6 -38,7 +38,7 @@@
  #include <drm/drm_edid.h>
  #include <drm/drm_fourcc.h>
  #include <drm/drm_modeset_lock.h>
+ #include <drm/drm_atomic.h>
  
  #include "drm_crtc_internal.h"
  #include "drm_internal.h"
@@@ -830,6 -831,7 +831,7 @@@ int drm_connector_init(struct drm_devic
                       const struct drm_connector_funcs *funcs,
                       int connector_type)
  {
+       struct drm_mode_config *config = &dev->mode_config;
        int ret;
        struct ida *connector_ida =
                &drm_connector_enum_list[connector_type].ida;
  
        /* We should add connectors at the end to avoid upsetting the connector
         * index too much. */
-       list_add_tail(&connector->head, &dev->mode_config.connector_list);
-       dev->mode_config.num_connector++;
+       list_add_tail(&connector->head, &config->connector_list);
+       config->num_connector++;
  
        if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
                drm_object_attach_property(&connector->base,
-                                             dev->mode_config.edid_property,
+                                             config->edid_property,
                                              0);
  
        drm_object_attach_property(&connector->base,
-                                     dev->mode_config.dpms_property, 0);
+                                     config->dpms_property, 0);
+       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+               drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
+       }
  
        connector->debugfs_entry = NULL;
  
@@@ -1168,6 -1174,7 +1174,7 @@@ int drm_universal_plane_init(struct drm
                             const uint32_t *formats, uint32_t format_count,
                             enum drm_plane_type type)
  {
+       struct drm_mode_config *config = &dev->mode_config;
        int ret;
  
        ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
        plane->possible_crtcs = possible_crtcs;
        plane->type = type;
  
-       list_add_tail(&plane->head, &dev->mode_config.plane_list);
-       dev->mode_config.num_total_plane++;
+       list_add_tail(&plane->head, &config->plane_list);
+       config->num_total_plane++;
        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
-               dev->mode_config.num_overlay_plane++;
+               config->num_overlay_plane++;
  
        drm_object_attach_property(&plane->base,
-                                  dev->mode_config.plane_type_property,
+                                  config->plane_type_property,
                                   plane->type);
  
+       if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+               drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+               drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+               drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+       }
        return 0;
  }
  EXPORT_SYMBOL(drm_universal_plane_init);
@@@ -1322,50 -1342,109 +1342,109 @@@ void drm_plane_force_disable(struct drm
  }
  EXPORT_SYMBOL(drm_plane_force_disable);
  
- static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
+ static int drm_mode_create_standard_properties(struct drm_device *dev)
  {
-       struct drm_property *edid;
-       struct drm_property *dpms;
-       struct drm_property *dev_path;
+       struct drm_property *prop;
  
        /*
         * Standard properties (apply to all connectors)
         */
-       edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+       prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
                                   DRM_MODE_PROP_IMMUTABLE,
                                   "EDID", 0);
-       dev->mode_config.edid_property = edid;
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.edid_property = prop;
  
-       dpms = drm_property_create_enum(dev, 0,
+       prop = drm_property_create_enum(dev, 0,
                                   "DPMS", drm_dpms_enum_list,
                                   ARRAY_SIZE(drm_dpms_enum_list));
-       dev->mode_config.dpms_property = dpms;
-       dev_path = drm_property_create(dev,
-                                      DRM_MODE_PROP_BLOB |
-                                      DRM_MODE_PROP_IMMUTABLE,
-                                      "PATH", 0);
-       dev->mode_config.path_property = dev_path;
-       dev->mode_config.tile_property = drm_property_create(dev,
-                                                            DRM_MODE_PROP_BLOB |
-                                                            DRM_MODE_PROP_IMMUTABLE,
-                                                            "TILE", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.dpms_property = prop;
  
-       return 0;
- }
+       prop = drm_property_create(dev,
+                                  DRM_MODE_PROP_BLOB |
+                                  DRM_MODE_PROP_IMMUTABLE,
+                                  "PATH", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.path_property = prop;
  
- static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
- {
-       struct drm_property *type;
+       prop = drm_property_create(dev,
+                                  DRM_MODE_PROP_BLOB |
+                                  DRM_MODE_PROP_IMMUTABLE,
+                                  "TILE", 0);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.tile_property = prop;
  
-       /*
-        * Standard properties (apply to all planes)
-        */
-       type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+       prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
                                        "type", drm_plane_type_enum_list,
                                        ARRAY_SIZE(drm_plane_type_enum_list));
-       dev->mode_config.plane_type_property = type;
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.plane_type_property = prop;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_X", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_x = prop;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_Y", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_y = prop;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_W", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_w = prop;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "SRC_H", 0, UINT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_src_h = prop;
+       prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_X", INT_MIN, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_x = prop;
+       prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_Y", INT_MIN, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_y = prop;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_W", 0, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_w = prop;
+       prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_H", 0, INT_MAX);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_h = prop;
+       prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+                       "FB_ID", DRM_MODE_OBJECT_FB);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_fb_id = prop;
+       prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+                       "CRTC_ID", DRM_MODE_OBJECT_CRTC);
+       if (!prop)
+               return -ENOMEM;
+       dev->mode_config.prop_crtc_id = prop;
  
        return 0;
  }
@@@ -1991,6 -2070,44 +2070,44 @@@ static struct drm_encoder *drm_connecto
        return connector->encoder;
  }
  
+ /* helper for getconnector and getproperties ioctls */
+ static int get_properties(struct drm_mode_object *obj, bool atomic,
+               uint32_t __user *prop_ptr, uint64_t __user *prop_values,
+               uint32_t *arg_count_props)
+ {
+       int props_count;
+       int i, ret, copied;
+       props_count = obj->properties->count;
+       if (!atomic)
+               props_count -= obj->properties->atomic_count;
+       if ((*arg_count_props >= props_count) && props_count) {
+               for (i = 0, copied = 0; copied < props_count; i++) {
+                       struct drm_property *prop = obj->properties->properties[i];
+                       uint64_t val;
+                       if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
+                               continue;
+                       ret = drm_object_property_get_value(obj, prop, &val);
+                       if (ret)
+                               return ret;
+                       if (put_user(prop->base.id, prop_ptr + copied))
+                               return -EFAULT;
+                       if (put_user(val, prop_values + copied))
+                               return -EFAULT;
+                       copied++;
+               }
+       }
+       *arg_count_props = props_count;
+       return 0;
+ }
  /**
   * drm_mode_getconnector - get connector configuration
   * @dev: drm device for the ioctl
@@@ -2012,15 -2129,12 +2129,12 @@@ int drm_mode_getconnector(struct drm_de
        struct drm_encoder *encoder;
        struct drm_display_mode *mode;
        int mode_count = 0;
-       int props_count = 0;
        int encoders_count = 0;
        int ret = 0;
        int copied = 0;
        int i;
        struct drm_mode_modeinfo u_mode;
        struct drm_mode_modeinfo __user *mode_ptr;
-       uint32_t __user *prop_ptr;
-       uint64_t __user *prop_values;
        uint32_t __user *encoder_ptr;
  
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
        DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
  
        mutex_lock(&dev->mode_config.mutex);
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
  
        connector = drm_connector_find(dev, out_resp->connector_id);
        if (!connector) {
                goto out;
        }
  
-       props_count = connector->properties.count;
        for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
                if (connector->encoder_ids[i] != 0)
                        encoders_count++;
        out_resp->mm_height = connector->display_info.height_mm;
        out_resp->subpixel = connector->display_info.subpixel_order;
        out_resp->connection = connector->status;
-       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
        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);
  
        /*
         * This ioctl is called twice, once to determine how much space is
        }
        out_resp->count_modes = mode_count;
  
-       if ((out_resp->count_props >= props_count) && props_count) {
-               copied = 0;
-               prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
-               prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
-               for (i = 0; i < connector->properties.count; i++) {
-                       if (put_user(connector->properties.ids[i],
-                                    prop_ptr + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       if (put_user(connector->properties.values[i],
-                                    prop_values + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       copied++;
-               }
-       }
-       out_resp->count_props = props_count;
+       ret = get_properties(&connector->base, file_priv->atomic,
+                       (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
+                       (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
+                       &out_resp->count_props);
+       if (ret)
+               goto out;
  
        if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
                copied = 0;
        out_resp->count_encoders = encoders_count;
  
  out:
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
        mutex_unlock(&dev->mode_config.mutex);
  
        return ret;
@@@ -2683,12 -2780,6 +2780,12 @@@ int drm_mode_setcrtc(struct drm_device 
                        goto out;
                }
  
 +              mode->status = drm_mode_validate_basic(mode);
 +              if (mode->status != MODE_OK) {
 +                      ret = -EINVAL;
 +                      goto out;
 +              }
 +
                drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
  
                ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
@@@ -3823,9 -3914,11 +3920,11 @@@ void drm_object_attach_property(struct 
                return;
        }
  
-       obj->properties->ids[count] = property->base.id;
+       obj->properties->properties[count] = property;
        obj->properties->values[count] = init_val;
        obj->properties->count++;
+       if (property->flags & DRM_MODE_PROP_ATOMIC)
+               obj->properties->atomic_count++;
  }
  EXPORT_SYMBOL(drm_object_attach_property);
  
@@@ -3848,7 -3941,7 +3947,7 @@@ int drm_object_property_set_value(struc
        int i;
  
        for (i = 0; i < obj->properties->count; i++) {
-               if (obj->properties->ids[i] == property->base.id) {
+               if (obj->properties->properties[i] == property) {
                        obj->properties->values[i] = val;
                        return 0;
                }
@@@ -3877,8 -3970,16 +3976,16 @@@ int drm_object_property_get_value(struc
  {
        int i;
  
+       /* read-only properties bypass atomic mechanism and still store
+        * their value in obj->properties->values[].. mostly to avoid
+        * having to deal w/ EDID and similar props in atomic paths:
+        */
+       if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
+                       !(property->flags & DRM_MODE_PROP_IMMUTABLE))
+               return drm_atomic_get_property(obj, property, val);
        for (i = 0; i < obj->properties->count; i++) {
-               if (obj->properties->ids[i] == property->base.id) {
+               if (obj->properties->properties[i] == property) {
                        *val = obj->properties->values[i];
                        return 0;
                }
@@@ -4194,14 -4295,24 +4301,24 @@@ int drm_mode_connector_update_edid_prop
  }
  EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
  
- static bool drm_property_change_is_valid(struct drm_property *property,
-                                        uint64_t value)
+ /* Some properties could refer to dynamic refcnt'd objects, or things that
+  * need special locking to handle lifetime issues (ie. to ensure the prop
+  * value doesn't become invalid part way through the property update due to
+  * race).  The value returned by reference via 'obj' should be passed back
+  * to drm_property_change_valid_put() after the property is set (and the
+  * object to which the property is attached has a chance to take it's own
+  * reference).
+  */
+ bool drm_property_change_valid_get(struct drm_property *property,
+                                        uint64_t value, struct drm_mode_object **ref)
  {
        int i;
  
        if (property->flags & DRM_MODE_PROP_IMMUTABLE)
                return false;
  
+       *ref = NULL;
        if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
                if (value < property->values[0] || value > property->values[1])
                        return false;
                /* Only the driver knows */
                return true;
        } else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
-               struct drm_mode_object *obj;
                /* a zero value for an object property translates to null: */
                if (value == 0)
                        return true;
-               /*
-                * NOTE: use _object_find() directly to bypass restriction on
-                * looking up refcnt'd objects (ie. fb's).  For a refcnt'd
-                * object this could race against object finalization, so it
-                * simply tells us that the object *was* valid.  Which is good
-                * enough.
-                */
-               obj = _object_find(property->dev, value, property->values[0]);
-               return obj != NULL;
+               /* handle refcnt'd objects specially: */
+               if (property->values[0] == DRM_MODE_OBJECT_FB) {
+                       struct drm_framebuffer *fb;
+                       fb = drm_framebuffer_lookup(property->dev, value);
+                       if (fb) {
+                               *ref = &fb->base;
+                               return true;
+                       } else {
+                               return false;
+                       }
+               } else {
+                       return _object_find(property->dev, value, property->values[0]) != NULL;
+               }
+       } else {
+               int i;
+               for (i = 0; i < property->num_values; i++)
+                       if (property->values[i] == value)
+                               return true;
+               return false;
        }
  
        for (i = 0; i < property->num_values; i++)
        return false;
  }
  
+ void drm_property_change_valid_put(struct drm_property *property,
+               struct drm_mode_object *ref)
+ {
+       if (!ref)
+               return;
+       if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
+               if (property->values[0] == DRM_MODE_OBJECT_FB)
+                       drm_framebuffer_unreference(obj_to_fb(ref));
+       }
+ }
  /**
   * drm_mode_connector_property_set_ioctl - set the current value of a connector property
   * @dev: DRM device
@@@ -4360,11 -4492,6 +4498,6 @@@ int drm_mode_obj_get_properties_ioctl(s
        struct drm_mode_obj_get_properties *arg = data;
        struct drm_mode_object *obj;
        int ret = 0;
-       int i;
-       int copied = 0;
-       int props_count = 0;
-       uint32_t __user *props_ptr;
-       uint64_t __user *prop_values_ptr;
  
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
                goto out;
        }
  
-       props_count = obj->properties->count;
+       ret = get_properties(obj, file_priv->atomic,
+                       (uint32_t __user *)(unsigned long)(arg->props_ptr),
+                       (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
+                       &arg->count_props);
  
-       /* This ioctl is called twice, once to determine how much space is
-        * needed, and the 2nd time to fill it. */
-       if ((arg->count_props >= props_count) && props_count) {
-               copied = 0;
-               props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
-               prop_values_ptr = (uint64_t __user *)(unsigned long)
-                                 (arg->prop_values_ptr);
-               for (i = 0; i < props_count; i++) {
-                       if (put_user(obj->properties->ids[i],
-                                    props_ptr + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       if (put_user(obj->properties->values[i],
-                                    prop_values_ptr + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
-                       copied++;
-               }
-       }
-       arg->count_props = props_count;
  out:
        drm_modeset_unlock_all(dev);
        return ret;
@@@ -4433,8 -4541,8 +4547,8 @@@ int drm_mode_obj_set_property_ioctl(str
        struct drm_mode_object *arg_obj;
        struct drm_mode_object *prop_obj;
        struct drm_property *property;
-       int ret = -EINVAL;
-       int i;
+       int i, ret = -EINVAL;
+       struct drm_mode_object *ref;
  
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
                goto out;
  
        for (i = 0; i < arg_obj->properties->count; i++)
-               if (arg_obj->properties->ids[i] == arg->prop_id)
+               if (arg_obj->properties->properties[i]->base.id == arg->prop_id)
                        break;
  
        if (i == arg_obj->properties->count)
        }
        property = obj_to_property(prop_obj);
  
-       if (!drm_property_change_is_valid(property, arg->value))
+       if (!drm_property_change_valid_get(property, arg->value, &ref))
                goto out;
  
        switch (arg_obj->type) {
                break;
        }
  
+       drm_property_change_valid_put(property, ref);
  out:
        drm_modeset_unlock_all(dev);
        return ret;
@@@ -5225,8 -5335,7 +5341,7 @@@ void drm_mode_config_init(struct drm_de
        idr_init(&dev->mode_config.tile_idr);
  
        drm_modeset_lock_all(dev);
-       drm_mode_create_standard_connector_properties(dev);
-       drm_mode_create_standard_plane_properties(dev);
+       drm_mode_create_standard_properties(dev);
        drm_modeset_unlock_all(dev);
  
        /* Just to be sure */
index 191968256c5822ae0a7964db31377e5ba7b0e0ce,f8f18e882f97b92e39856baab23d47d14dffa96a..2c396540e279efdbfdc0cd9c0038728d04c7e65b
@@@ -23,41 -23,10 +23,41 @@@ struct msm_commit 
        struct drm_atomic_state *state;
        uint32_t fence;
        struct msm_fence_cb fence_cb;
 +      uint32_t crtc_mask;
  };
  
  static void fence_cb(struct msm_fence_cb *cb);
  
 +/* block until specified crtcs are no longer pending update, and
 + * atomically mark them as pending update
 + */
 +static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
 +{
 +      int ret;
 +
 +      spin_lock(&priv->pending_crtcs_event.lock);
 +      ret = wait_event_interruptible_locked(priv->pending_crtcs_event,
 +                      !(priv->pending_crtcs & crtc_mask));
 +      if (ret == 0) {
 +              DBG("start: %08x", crtc_mask);
 +              priv->pending_crtcs |= crtc_mask;
 +      }
 +      spin_unlock(&priv->pending_crtcs_event.lock);
 +
 +      return ret;
 +}
 +
 +/* clear specified crtcs (no longer pending update)
 + */
 +static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
 +{
 +      spin_lock(&priv->pending_crtcs_event.lock);
 +      DBG("end: %08x", crtc_mask);
 +      priv->pending_crtcs &= ~crtc_mask;
 +      wake_up_all_locked(&priv->pending_crtcs_event);
 +      spin_unlock(&priv->pending_crtcs_event.lock);
 +}
 +
  static struct msm_commit *new_commit(struct drm_atomic_state *state)
  {
        struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
@@@ -89,27 -58,12 +89,27 @@@ static void complete_commit(struct msm_
  
        drm_atomic_helper_commit_post_planes(dev, state);
  
 +      /* NOTE: _wait_for_vblanks() only waits for vblank on
 +       * enabled CRTCs.  So we end up faulting when disabling
 +       * due to (potentially) unref'ing the outgoing fb's
 +       * before the vblank when the disable has latched.
 +       *
 +       * But if it did wait on disabled (or newly disabled)
 +       * CRTCs, that would be racy (ie. we could have missed
 +       * the irq.  We need some way to poll for pipe shut
 +       * down.  Or just live with occasionally hitting the
 +       * timeout in the CRTC disable path (which really should
 +       * not be critical path)
 +       */
 +
        drm_atomic_helper_wait_for_vblanks(dev, state);
  
        drm_atomic_helper_cleanup_planes(dev, state);
  
        drm_atomic_state_free(state);
  
 +      end_atomic(dev->dev_private, c->crtc_mask);
 +
        kfree(c);
  }
  
@@@ -127,6 -81,26 +127,26 @@@ static void add_fb(struct msm_commit *c
  }
  
  
+ int msm_atomic_check(struct drm_device *dev,
+                    struct drm_atomic_state *state)
+ {
+       int ret;
+       /*
+        * msm ->atomic_check can update ->mode_changed for pixel format
+        * changes, hence must be run before we check the modeset changes.
+        */
+       ret = drm_atomic_helper_check_planes(dev, state);
+       if (ret)
+               return ret;
+       ret = drm_atomic_helper_check_modeset(dev, state);
+       if (ret)
+               return ret;
+       return ret;
+ }
  /**
   * drm_atomic_helper_commit - commit validated state object
   * @dev: DRM device
  int msm_atomic_commit(struct drm_device *dev,
                struct drm_atomic_state *state, bool async)
  {
 -      struct msm_commit *c;
        int nplanes = dev->mode_config.num_total_plane;
 +      int ncrtcs = dev->mode_config.num_crtc;
 +      struct msm_commit *c;
        int i, ret;
  
        ret = drm_atomic_helper_prepare_planes(dev, state);
                return ret;
  
        c = new_commit(state);
 +      if (!c)
 +              return -ENOMEM;
 +
 +      /*
 +       * Figure out what crtcs we have:
 +       */
 +      for (i = 0; i < ncrtcs; i++) {
 +              struct drm_crtc *crtc = state->crtcs[i];
 +              if (!crtc)
 +                      continue;
 +              c->crtc_mask |= (1 << drm_crtc_index(crtc));
 +      }
  
        /*
         * Figure out what fence to wait for:
                        add_fb(c, new_state->fb);
        }
  
 +      /*
 +       * Wait for pending updates on any of the same crtc's and then
 +       * mark our set of crtc's as busy:
 +       */
 +      ret = start_atomic(dev->dev_private, c->crtc_mask);
 +      if (ret)
 +              return ret;
 +
        /*
         * This is the point of no return - everything below never fails except
         * when the hw goes bonghits. Which means we can commit the new state on
index 9a61546a0b05276cd313b0877306b02930fa2fa5,473e4d6051e9f0b1e44828405dc1329c4657bb9b..f1ebedde6346d6c966bceaf0b351a549d8d87d7f
@@@ -29,7 -29,7 +29,7 @@@ static void msm_fb_output_poll_changed(
  static const struct drm_mode_config_funcs mode_config_funcs = {
        .fb_create = msm_framebuffer_create,
        .output_poll_changed = msm_fb_output_poll_changed,
-       .atomic_check = drm_atomic_helper_check,
+       .atomic_check = msm_atomic_check,
        .atomic_commit = msm_atomic_commit,
  };
  
@@@ -193,7 -193,6 +193,7 @@@ static int msm_load(struct drm_device *
  
        priv->wq = alloc_ordered_workqueue("msm", 0);
        init_waitqueue_head(&priv->fence_event);
 +      init_waitqueue_head(&priv->pending_crtcs_event);
  
        INIT_LIST_HEAD(&priv->inactive_list);
        INIT_LIST_HEAD(&priv->fence_cbs);
@@@ -1013,6 -1012,7 +1013,6 @@@ static struct platform_driver msm_platf
        .probe      = msm_pdev_probe,
        .remove     = msm_pdev_remove,
        .driver     = {
 -              .owner  = THIS_MODULE,
                .name   = "msm",
                .of_match_table = dt_match,
                .pm     = &msm_pm_ops,
index b69ef2d5a26c0a0afa9896ed02a88a087f9cebfe,d408e02e4ee5bd4d36e0b1ab0f789917b8641454..22e5391a7ce8f321d06d3bd0ec7dd1902d8b2228
@@@ -96,10 -96,6 +96,10 @@@ struct msm_drm_private 
        /* callbacks deferred until bo is inactive: */
        struct list_head fence_cbs;
  
 +      /* crtcs pending async atomic updates: */
 +      uint32_t pending_crtcs;
 +      wait_queue_head_t pending_crtcs_event;
 +
        /* registered MMUs: */
        unsigned int num_mmus;
        struct msm_mmu *mmus[NUM_DOMAINS];
@@@ -148,6 -144,8 +148,8 @@@ void __msm_fence_worker(struct work_str
                (_cb)->func = _func;                         \
        } while (0)
  
+ int msm_atomic_check(struct drm_device *dev,
+                    struct drm_atomic_state *state);
  int msm_atomic_commit(struct drm_device *dev,
                struct drm_atomic_state *state, bool async);
  
diff --combined include/drm/drmP.h
index a5f6a1f563c4f5b658fb43634af72ef1395766ec,0f7115e988a075fe393858abff82128408e6f4c0..e928625a9da0be41b7b03508a19f3df2cfb8acb5
@@@ -143,6 -143,7 +143,7 @@@ void drm_err(const char *format, ...)
  #define DRIVER_MODESET     0x2000
  #define DRIVER_PRIME       0x4000
  #define DRIVER_RENDER      0x8000
+ #define DRIVER_ATOMIC      0x10000
  
  /***********************************************************************/
  /** \name Macros to make printk easier */
@@@ -283,6 -284,8 +284,8 @@@ struct drm_file 
         * in the plane list
         */
        unsigned universal_planes:1;
+       /* true if client understands atomic properties */
+       unsigned atomic:1;
  
        struct pid *pid;
        kuid_t uid;
@@@ -744,6 -747,8 +747,6 @@@ struct drm_device 
  
        /** \name Context support */
        /*@{ */
 -      bool irq_enabled;               /**< True if irq handler is enabled */
 -      int irq;
  
        __volatile__ long context_flag; /**< Context swapping flag */
        int last_context;               /**< Last current context */
  
        /** \name VBLANK IRQ support */
        /*@{ */
 +      bool irq_enabled;
 +      int irq;
  
        /*
         * At load time, disabling the vblank interrupt won't be allowed since
@@@ -901,15 -904,11 +904,15 @@@ extern int drm_vblank_init(struct drm_d
  extern int drm_wait_vblank(struct drm_device *dev, void *data,
                           struct drm_file *filp);
  extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
 +extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc);
  extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                                     struct timeval *vblanktime);
  extern void drm_send_vblank_event(struct drm_device *dev, int crtc,
                                     struct drm_pending_vblank_event *e);
 +extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
 +                                     struct drm_pending_vblank_event *e);
  extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
 +extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
  extern int drm_vblank_get(struct drm_device *dev, int crtc);
  extern void drm_vblank_put(struct drm_device *dev, int crtc);
  extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
@@@ -954,6 -953,7 +957,7 @@@ extern void drm_master_put(struct drm_m
  extern void drm_put_dev(struct drm_device *dev);
  extern void drm_unplug_dev(struct drm_device *dev);
  extern unsigned int drm_debug;
+ extern bool drm_atomic;
  
                                /* Debugfs support */
  #if defined(CONFIG_DEBUG_FS)
diff --combined include/drm/drm_crtc.h
index 291239f2fafca3b75091e6333f40f5dc5d302a38,1dcfb685d15f27bee0687d1e3c5f305f9909b403..6588bffb65180458e968f9f3230a2b4b3174f838
@@@ -63,8 -63,16 +63,16 @@@ struct drm_mode_object 
  
  #define DRM_OBJECT_MAX_PROPERTY 24
  struct drm_object_properties {
-       int count;
-       uint32_t ids[DRM_OBJECT_MAX_PROPERTY];
+       int count, atomic_count;
+       /* NOTE: if we ever start dynamically destroying properties (ie.
+        * not at drm_mode_config_cleanup() time), then we'd have to do
+        * a better job of detaching property from mode objects to avoid
+        * dangling property pointers:
+        */
+       struct drm_property *properties[DRM_OBJECT_MAX_PROPERTY];
+       /* do not read/write values directly, but use drm_object_property_get_value()
+        * and drm_object_property_set_value():
+        */
        uint64_t values[DRM_OBJECT_MAX_PROPERTY];
  };
  
@@@ -237,7 -245,9 +245,9 @@@ struct drm_atomic_state
  
  /**
   * struct drm_crtc_state - mutable CRTC state
+  * @crtc: backpointer to the CRTC
   * @enable: whether the CRTC should be enabled, gates all other state
+  * @active: whether the CRTC is actively displaying (used for DPMS)
   * @mode_changed: for use by helpers and drivers when computing state updates
   * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
   * @last_vblank_count: for helpers and drivers to capture the vblank of the
   * @event: optional pointer to a DRM event to signal upon completion of the
   *    state update
   * @state: backpointer to global drm_atomic_state
+  *
+  * Note that the distinction between @enable and @active is rather subtile:
+  * Flipping @active while @enable is set without changing anything else may
+  * never return in a failure from the ->atomic_check callback. Userspace assumes
+  * that a DPMS On will always succeed. In other words: @enable controls resource
+  * assignment, @active controls the actual hardware state.
   */
  struct drm_crtc_state {
+       struct drm_crtc *crtc;
        bool enable;
+       bool active;
  
        /* computed state bits used by helpers and drivers */
        bool planes_changed : 1;
   * @atomic_duplicate_state: duplicate the atomic state for this CRTC
   * @atomic_destroy_state: destroy an atomic state for this CRTC
   * @atomic_set_property: set a property on an atomic state for this CRTC
+  *    (do not call directly, use drm_atomic_crtc_set_property())
+  * @atomic_get_property: get a property on an atomic state for this CRTC
+  *    (do not call directly, use drm_atomic_crtc_get_property())
   *
   * The drm_crtc_funcs structure is the central CRTC management structure
   * in the DRM.  Each CRTC controls one or more connectors (note that the name
@@@ -351,6 -373,10 +373,10 @@@ struct drm_crtc_funcs 
                                   struct drm_crtc_state *state,
                                   struct drm_property *property,
                                   uint64_t val);
+       int (*atomic_get_property)(struct drm_crtc *crtc,
+                                  const struct drm_crtc_state *state,
+                                  struct drm_property *property,
+                                  uint64_t *val);
  };
  
  /**
@@@ -449,11 -475,14 +475,14 @@@ struct drm_crtc 
  
  /**
   * struct drm_connector_state - mutable connector state
+  * @connector: backpointer to the connector
   * @crtc: CRTC to connect connector to, NULL if disabled
   * @best_encoder: can be used by helpers and drivers to select the encoder
   * @state: backpointer to global drm_atomic_state
   */
  struct drm_connector_state {
+       struct drm_connector *connector;
        struct drm_crtc *crtc;  /* do not write directly, use drm_atomic_set_crtc_for_connector() */
  
        struct drm_encoder *best_encoder;
  
  /**
   * struct drm_connector_funcs - control connectors on a given device
 - * @dpms: set power state (see drm_crtc_funcs above)
 + * @dpms: set power state
   * @save: save connector state
   * @restore: restore connector state
   * @reset: reset connector after state has been invalidated (e.g. resume)
   * @atomic_duplicate_state: duplicate the atomic state for this connector
   * @atomic_destroy_state: destroy an atomic state for this connector
   * @atomic_set_property: set a property on an atomic state for this connector
+  *    (do not call directly, use drm_atomic_connector_set_property())
+  * @atomic_get_property: get a property on an atomic state for this connector
+  *    (do not call directly, use drm_atomic_connector_get_property())
   *
   * Each CRTC may have one or more connectors attached to it.  The functions
   * below allow the core DRM code to control connectors, enumerate available modes,
@@@ -508,6 -540,10 +540,10 @@@ struct drm_connector_funcs 
                                   struct drm_connector_state *state,
                                   struct drm_property *property,
                                   uint64_t val);
+       int (*atomic_get_property)(struct drm_connector *connector,
+                                  const struct drm_connector_state *state,
+                                  struct drm_property *property,
+                                  uint64_t *val);
  };
  
  /**
@@@ -693,6 -729,7 +729,7 @@@ struct drm_connector 
  
  /**
   * struct drm_plane_state - mutable plane state
+  * @plane: backpointer to the plane
   * @crtc: currently bound CRTC, NULL if disabled
   * @fb: currently bound framebuffer
   * @fence: optional fence to wait for before scanning out @fb
   * @state: backpointer to global drm_atomic_state
   */
  struct drm_plane_state {
+       struct drm_plane *plane;
        struct drm_crtc *crtc;   /* do not write directly, use drm_atomic_set_crtc_for_plane() */
        struct drm_framebuffer *fb;  /* do not write directly, use drm_atomic_set_fb_for_plane() */
        struct fence *fence;
   * @atomic_duplicate_state: duplicate the atomic state for this plane
   * @atomic_destroy_state: destroy an atomic state for this plane
   * @atomic_set_property: set a property on an atomic state for this plane
+  *    (do not call directly, use drm_atomic_plane_set_property())
+  * @atomic_get_property: get a property on an atomic state for this plane
+  *    (do not call directly, use drm_atomic_plane_get_property())
   */
  struct drm_plane_funcs {
        int (*update_plane)(struct drm_plane *plane,
                                   struct drm_plane_state *state,
                                   struct drm_property *property,
                                   uint64_t val);
+       int (*atomic_get_property)(struct drm_plane *plane,
+                                  const struct drm_plane_state *state,
+                                  struct drm_property *property,
+                                  uint64_t *val);
  };
  
  enum drm_plane_type {
@@@ -856,7 -902,7 +902,7 @@@ struct drm_bridge 
  /**
   * struct struct drm_atomic_state - the global state object for atomic updates
   * @dev: parent DRM device
-  * @flags: state flags like async update
+  * @allow_modeset: allow full modeset
   * @planes: pointer to array of plane pointers
   * @plane_states: pointer to array of plane states pointers
   * @crtcs: pointer to array of CRTC pointers
   */
  struct drm_atomic_state {
        struct drm_device *dev;
-       uint32_t flags;
+       bool allow_modeset : 1;
        struct drm_plane **planes;
        struct drm_plane_state **plane_states;
        struct drm_crtc **crtcs;
@@@ -1053,6 -1099,16 +1099,16 @@@ struct drm_mode_config 
        struct drm_property *tile_property;
        struct drm_property *plane_type_property;
        struct drm_property *rotation_property;
+       struct drm_property *prop_src_x;
+       struct drm_property *prop_src_y;
+       struct drm_property *prop_src_w;
+       struct drm_property *prop_src_h;
+       struct drm_property *prop_crtc_x;
+       struct drm_property *prop_crtc_y;
+       struct drm_property *prop_crtc_w;
+       struct drm_property *prop_crtc_h;
+       struct drm_property *prop_fb_id;
+       struct drm_property *prop_crtc_id;
  
        /* DVI-I properties */
        struct drm_property *dvi_i_subconnector_property;
@@@ -1290,6 -1346,10 +1346,10 @@@ extern int drm_mode_create_scaling_mode
  extern int drm_mode_create_aspect_ratio_property(struct drm_device *dev);
  extern int drm_mode_create_dirty_info_property(struct drm_device *dev);
  extern int drm_mode_create_suggested_offset_properties(struct drm_device *dev);
+ extern bool drm_property_change_valid_get(struct drm_property *property,
+                                        uint64_t value, struct drm_mode_object **ref);
+ extern void drm_property_change_valid_put(struct drm_property *property,
+               struct drm_mode_object *ref);
  
  extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
                                             struct drm_encoder *encoder);
@@@ -1381,6 -1441,8 +1441,8 @@@ extern int drm_mode_obj_set_property_io
  extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
                                       struct drm_property *property,
                                       uint64_t value);
+ extern int drm_mode_atomic_ioctl(struct drm_device *dev,
+                                void *data, struct drm_file *file_priv);
  
  extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                                 int *bpp);