drm: Prefer kcalloc() over kzalloc() with multiply
[pandora-kernel.git] / drivers / gpu / drm / drm_crtc.c
index 3ea31bc..45e17df 100644 (file)
@@ -61,8 +61,8 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
 /*
  * Global properties
  */
-static const struct drm_prop_enum_list drm_dpms_enum_list[] =
-{      { DRM_MODE_DPMS_ON, "On" },
+static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
+       { DRM_MODE_DPMS_ON, "On" },
        { DRM_MODE_DPMS_STANDBY, "Standby" },
        { DRM_MODE_DPMS_SUSPEND, "Suspend" },
        { DRM_MODE_DPMS_OFF, "Off" }
@@ -70,8 +70,7 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] =
 
 DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
 
-static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
        { DRM_PLANE_TYPE_OVERLAY, "Overlay" },
        { DRM_PLANE_TYPE_PRIMARY, "Primary" },
        { DRM_PLANE_TYPE_CURSOR, "Cursor" },
@@ -80,8 +79,7 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
 /*
  * Optional properties
  */
-static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
        { DRM_MODE_SCALE_NONE, "None" },
        { DRM_MODE_SCALE_FULLSCREEN, "Full" },
        { DRM_MODE_SCALE_CENTER, "Center" },
@@ -97,8 +95,7 @@ static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
 /*
  * Non-global properties, but "required" for certain connectors.
  */
-static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
        { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
@@ -106,8 +103,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
 
 DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
 
-static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
        { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
@@ -116,8 +112,7 @@ static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
 DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
                 drm_dvi_i_subconnector_enum_list)
 
-static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
@@ -127,8 +122,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
 
 DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
 
-static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
        { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
        { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
        { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
@@ -154,8 +148,8 @@ struct drm_conn_prop_enum_list {
 /*
  * Connector and encoder types.
  */
-static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
-{      { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
+static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
+       { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
        { DRM_MODE_CONNECTOR_VGA, "VGA" },
        { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
        { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
@@ -174,8 +168,8 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
        { DRM_MODE_CONNECTOR_DSI, "DSI" },
 };
 
-static const struct drm_prop_enum_list drm_encoder_enum_list[] =
-{      { DRM_MODE_ENCODER_NONE, "None" },
+static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
+       { DRM_MODE_ENCODER_NONE, "None" },
        { DRM_MODE_ENCODER_DAC, "DAC" },
        { DRM_MODE_ENCODER_TMDS, "TMDS" },
        { DRM_MODE_ENCODER_LVDS, "LVDS" },
@@ -185,8 +179,7 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] =
        { DRM_MODE_ENCODER_DPMST, "DP MST" },
 };
 
-static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
        { SubPixelUnknown, "Unknown" },
        { SubPixelHorizontalRGB, "Horizontal RGB" },
        { SubPixelHorizontalBGR, "Horizontal BGR" },
@@ -683,7 +676,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        drm_modeset_lock_init(&crtc->mutex);
        ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
        if (ret)
-               goto out;
+               return ret;
 
        crtc->base.properties = &crtc->properties;
 
@@ -697,9 +690,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
        if (cursor)
                cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
 
- out:
-
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(drm_crtc_init_with_planes);
 
@@ -723,6 +714,12 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
        drm_mode_object_put(dev, &crtc->base);
        list_del(&crtc->head);
        dev->mode_config.num_crtc--;
+
+       WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
+       if (crtc->state && crtc->funcs->atomic_destroy_state)
+               crtc->funcs->atomic_destroy_state(crtc, crtc->state);
+
+       memset(crtc, 0, sizeof(*crtc));
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
@@ -766,7 +763,6 @@ static void drm_mode_remove(struct drm_connector *connector,
 /**
  * drm_connector_get_cmdline_mode - reads the user's cmdline mode
  * @connector: connector to quwery
- * @mode: returned mode
  *
  * The kernel supports per-connector configration of its consoles through
  * use of the video= parameter. This function parses that option and
@@ -870,6 +866,8 @@ int drm_connector_init(struct drm_device *dev,
 
        drm_connector_get_cmdline_mode(connector);
 
+       /* 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++;
 
@@ -919,6 +917,13 @@ void drm_connector_cleanup(struct drm_connector *connector)
        connector->name = NULL;
        list_del(&connector->head);
        dev->mode_config.num_connector--;
+
+       WARN_ON(connector->state && !connector->funcs->atomic_destroy_state);
+       if (connector->state && connector->funcs->atomic_destroy_state)
+               connector->funcs->atomic_destroy_state(connector,
+                                                      connector->state);
+
+       memset(connector, 0, sizeof(*connector));
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
@@ -933,6 +938,9 @@ unsigned int drm_connector_index(struct drm_connector *connector)
 {
        unsigned int index = 0;
        struct drm_connector *tmp;
+       struct drm_mode_config *config = &connector->dev->mode_config;
+
+       WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
        list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
                if (tmp == connector)
@@ -1057,6 +1065,8 @@ void drm_bridge_cleanup(struct drm_bridge *bridge)
        list_del(&bridge->head);
        dev->mode_config.num_bridge--;
        drm_modeset_unlock_all(dev);
+
+       memset(bridge, 0, sizeof(*bridge));
 }
 EXPORT_SYMBOL(drm_bridge_cleanup);
 
@@ -1120,13 +1130,15 @@ EXPORT_SYMBOL(drm_encoder_init);
 void drm_encoder_cleanup(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
+
        drm_modeset_lock_all(dev);
        drm_mode_object_put(dev, &encoder->base);
        kfree(encoder->name);
-       encoder->name = NULL;
        list_del(&encoder->head);
        dev->mode_config.num_encoder--;
        drm_modeset_unlock_all(dev);
+
+       memset(encoder, 0, sizeof(*encoder));
 }
 EXPORT_SYMBOL(drm_encoder_cleanup);
 
@@ -1153,11 +1165,11 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
 {
        int ret;
 
-       drm_modeset_lock_all(dev);
-
        ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
        if (ret)
-               goto out;
+               return ret;
+
+       drm_modeset_lock_init(&plane->mutex);
 
        plane->base.properties = &plane->properties;
        plane->dev = dev;
@@ -1167,8 +1179,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
        if (!plane->format_types) {
                DRM_DEBUG_KMS("out of memory when allocating plane\n");
                drm_mode_object_put(dev, &plane->base);
-               ret = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
 
        memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
@@ -1185,10 +1196,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
                                   dev->mode_config.plane_type_property,
                                   plane->type);
 
- out:
-       drm_modeset_unlock_all(dev);
-
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(drm_universal_plane_init);
 
@@ -1246,6 +1254,12 @@ void drm_plane_cleanup(struct drm_plane *plane)
        if (plane->type == DRM_PLANE_TYPE_OVERLAY)
                dev->mode_config.num_overlay_plane--;
        drm_modeset_unlock_all(dev);
+
+       WARN_ON(plane->state && !plane->funcs->atomic_destroy_state);
+       if (plane->state && plane->funcs->atomic_destroy_state)
+               plane->funcs->atomic_destroy_state(plane, plane->state);
+
+       memset(plane, 0, sizeof(*plane));
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
@@ -1388,12 +1402,13 @@ EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
  * responsible for allocating a list of format names and passing them to
  * this routine.
  */
-int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
+int drm_mode_create_tv_properties(struct drm_device *dev,
+                                 unsigned int num_modes,
                                  char *modes[])
 {
        struct drm_property *tv_selector;
        struct drm_property *tv_subconnector;
-       int i;
+       unsigned int i;
 
        if (dev->mode_config.tv_select_subconnector_property)
                return 0;
@@ -1491,7 +1506,7 @@ EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
  * connectors.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_create_aspect_ratio_property(struct drm_device *dev)
 {
@@ -1535,6 +1550,30 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
 
+/**
+ * drm_mode_create_suggested_offset_properties - create suggests offset properties
+ * @dev: DRM device
+ *
+ * Create the the suggested x/y offset property for connectors.
+ */
+int drm_mode_create_suggested_offset_properties(struct drm_device *dev)
+{
+       if (dev->mode_config.suggested_x_property && dev->mode_config.suggested_y_property)
+               return 0;
+
+       dev->mode_config.suggested_x_property =
+               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested X", 0, 0xffffffff);
+
+       dev->mode_config.suggested_y_property =
+               drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, "suggested Y", 0, 0xffffffff);
+
+       if (dev->mode_config.suggested_x_property == NULL ||
+           dev->mode_config.suggested_y_property == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties);
+
 static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
 {
        uint32_t total_objects = 0;
@@ -1544,7 +1583,7 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
        total_objects += dev->mode_config.num_encoder;
        total_objects += dev->mode_config.num_bridge;
 
-       group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
+       group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL);
        if (!group->id_list)
                return -ENOMEM;
 
@@ -1651,7 +1690,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
  * the caller.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 static int drm_crtc_convert_umode(struct drm_display_mode *out,
                                  const struct drm_mode_modeinfo *in)
@@ -1694,7 +1733,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getresources(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
@@ -1745,7 +1784,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        card_res->count_fbs = fb_count;
        mutex_unlock(&file_priv->fbs_lock);
 
-       drm_modeset_lock_all(dev);
+       /* mode_config.mutex protects the connector list against e.g. DP MST
+        * connector hot-adding. CRTC/Plane lists are invariant. */
+       mutex_lock(&dev->mode_config.mutex);
        if (!drm_is_primary_client(file_priv)) {
 
                mode_group = NULL;
@@ -1865,7 +1906,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
                  card_res->count_connectors, card_res->count_encoders);
 
 out:
-       drm_modeset_unlock_all(dev);
+       mutex_unlock(&dev->mode_config.mutex);
        return ret;
 }
 
@@ -1880,26 +1921,22 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getcrtc(struct drm_device *dev,
                     void *data, struct drm_file *file_priv)
 {
        struct drm_mode_crtc *crtc_resp = data;
        struct drm_crtc *crtc;
-       int ret = 0;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
-
        crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
-       if (!crtc) {
-               ret = -ENOENT;
-               goto out;
-       }
+       if (!crtc)
+               return -ENOENT;
 
+       drm_modeset_lock_crtc(crtc, crtc->primary);
        crtc_resp->x = crtc->x;
        crtc_resp->y = crtc->y;
        crtc_resp->gamma_size = crtc->gamma_size;
@@ -1916,10 +1953,9 @@ int drm_mode_getcrtc(struct drm_device *dev,
        } else {
                crtc_resp->mode_valid = 0;
        }
+       drm_modeset_unlock_crtc(crtc);
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
@@ -1935,6 +1971,15 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
        return true;
 }
 
+static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *connector)
+{
+       /* For atomic drivers only state objects are synchronously updated and
+        * protected by modeset locks, so check those first. */
+       if (connector->state)
+               return connector->state->best_encoder;
+       return connector->encoder;
+}
+
 /**
  * drm_mode_getconnector - get connector configuration
  * @dev: drm device for the ioctl
@@ -1946,13 +1991,14 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getconnector(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
        struct drm_mode_get_connector *out_resp = data;
        struct drm_connector *connector;
+       struct drm_encoder *encoder;
        struct drm_display_mode *mode;
        int mode_count = 0;
        int props_count = 0;
@@ -2008,8 +2054,10 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
        out_resp->subpixel = connector->display_info.subpixel_order;
        out_resp->connection = connector->status;
        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
-       if (connector->encoder)
-               out_resp->encoder_id = connector->encoder->base.id;
+
+       encoder = drm_connector_get_encoder(connector);
+       if (encoder)
+               out_resp->encoder_id = encoder->base.id;
        else
                out_resp->encoder_id = 0;
        drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -2079,6 +2127,33 @@ out:
        return ret;
 }
 
+static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
+{
+       struct drm_connector *connector;
+       struct drm_device *dev = encoder->dev;
+       bool uses_atomic = false;
+
+       /* For atomic drivers only state objects are synchronously updated and
+        * protected by modeset locks, so check those first. */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->state)
+                       continue;
+
+               uses_atomic = true;
+
+               if (connector->state->best_encoder != encoder)
+                       continue;
+
+               return connector->state->crtc;
+       }
+
+       /* Don't return stale data (e.g. pending async disable). */
+       if (uses_atomic)
+               return NULL;
+
+       return encoder->crtc;
+}
+
 /**
  * drm_mode_getencoder - get encoder configuration
  * @dev: drm device for the ioctl
@@ -2090,37 +2165,38 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getencoder(struct drm_device *dev, void *data,
                        struct drm_file *file_priv)
 {
        struct drm_mode_get_encoder *enc_resp = data;
        struct drm_encoder *encoder;
-       int ret = 0;
+       struct drm_crtc *crtc;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
        encoder = drm_encoder_find(dev, enc_resp->encoder_id);
-       if (!encoder) {
-               ret = -ENOENT;
-               goto out;
-       }
+       if (!encoder)
+               return -ENOENT;
 
-       if (encoder->crtc)
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+       crtc = drm_encoder_get_crtc(encoder);
+       if (crtc)
+               enc_resp->crtc_id = crtc->base.id;
+       else if (encoder->crtc)
                enc_resp->crtc_id = encoder->crtc->base.id;
        else
                enc_resp->crtc_id = 0;
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
        enc_resp->encoder_type = encoder->encoder_type;
        enc_resp->encoder_id = encoder->base.id;
        enc_resp->possible_crtcs = encoder->possible_crtcs;
        enc_resp->possible_clones = encoder->possible_clones;
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 /**
@@ -2134,7 +2210,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getplane_res(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
@@ -2143,13 +2219,12 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
        struct drm_mode_config *config;
        struct drm_plane *plane;
        uint32_t __user *plane_ptr;
-       int copied = 0, ret = 0;
+       int copied = 0;
        unsigned num_planes;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
        config = &dev->mode_config;
 
        if (file_priv->universal_planes)
@@ -2165,6 +2240,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
            (plane_resp->count_planes >= num_planes)) {
                plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 
+               /* Plane lists are invariant, no locking needed. */
                list_for_each_entry(plane, &config->plane_list, head) {
                        /*
                         * Unless userspace set the 'universal planes'
@@ -2174,18 +2250,14 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
                            !file_priv->universal_planes)
                                continue;
 
-                       if (put_user(plane->base.id, plane_ptr + copied)) {
-                               ret = -EFAULT;
-                               goto out;
-                       }
+                       if (put_user(plane->base.id, plane_ptr + copied))
+                               return -EFAULT;
                        copied++;
                }
        }
        plane_resp->count_planes = num_planes;
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 /**
@@ -2199,7 +2271,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getplane(struct drm_device *dev, void *data,
                      struct drm_file *file_priv)
@@ -2207,18 +2279,15 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
        struct drm_mode_get_plane *plane_resp = data;
        struct drm_plane *plane;
        uint32_t __user *format_ptr;
-       int ret = 0;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
 
-       drm_modeset_lock_all(dev);
        plane = drm_plane_find(dev, plane_resp->plane_id);
-       if (!plane) {
-               ret = -ENOENT;
-               goto out;
-       }
+       if (!plane)
+               return -ENOENT;
 
+       drm_modeset_lock(&plane->mutex, NULL);
        if (plane->crtc)
                plane_resp->crtc_id = plane->crtc->base.id;
        else
@@ -2228,6 +2297,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
                plane_resp->fb_id = plane->fb->base.id;
        else
                plane_resp->fb_id = 0;
+       drm_modeset_unlock(&plane->mutex);
 
        plane_resp->plane_id = plane->base.id;
        plane_resp->possible_crtcs = plane->possible_crtcs;
@@ -2243,15 +2313,12 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
                if (copy_to_user(format_ptr,
                                 plane->format_types,
                                 sizeof(uint32_t) * plane->format_count)) {
-                       ret = -EFAULT;
-                       goto out;
+                       return -EFAULT;
                }
        }
        plane_resp->count_format_types = plane->format_count;
 
-out:
-       drm_modeset_unlock_all(dev);
-       return ret;
+       return 0;
 }
 
 /*
@@ -2274,7 +2341,7 @@ static int __setplane_internal(struct drm_plane *plane,
 {
        int ret = 0;
        unsigned int fb_width, fb_height;
-       int i;
+       unsigned int i;
 
        /* No fb means shut it down */
        if (!fb) {
@@ -2378,13 +2445,12 @@ static int setplane_internal(struct drm_plane *plane,
  * valid crtc).
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_setplane(struct drm_device *dev, void *data,
                      struct drm_file *file_priv)
 {
        struct drm_mode_set_plane *plane_req = data;
-       struct drm_mode_object *obj;
        struct drm_plane *plane;
        struct drm_crtc *crtc = NULL;
        struct drm_framebuffer *fb = NULL;
@@ -2407,14 +2473,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
         * First, find the plane, crtc, and fb objects.  If not available,
         * we don't bother to call the driver.
         */
-       obj = drm_mode_object_find(dev, plane_req->plane_id,
-                                  DRM_MODE_OBJECT_PLANE);
-       if (!obj) {
+       plane = drm_plane_find(dev, plane_req->plane_id);
+       if (!plane) {
                DRM_DEBUG_KMS("Unknown plane ID %d\n",
                              plane_req->plane_id);
                return -ENOENT;
        }
-       plane = obj_to_plane(obj);
 
        if (plane_req->fb_id) {
                fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
@@ -2424,14 +2488,12 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
                        return -ENOENT;
                }
 
-               obj = drm_mode_object_find(dev, plane_req->crtc_id,
-                                          DRM_MODE_OBJECT_CRTC);
-               if (!obj) {
+               crtc = drm_crtc_find(dev, plane_req->crtc_id);
+               if (!crtc) {
                        DRM_DEBUG_KMS("Unknown crtc ID %d\n",
                                      plane_req->crtc_id);
                        return -ENOENT;
                }
-               crtc = obj_to_crtc(obj);
        }
 
        /*
@@ -2451,9 +2513,9 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
  *
  * This is a little helper to wrap internal calls to the ->set_config driver
  * interface. The only thing it adds is correct refcounting dance.
- * 
+ *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_set_config_internal(struct drm_mode_set *set)
 {
@@ -2546,7 +2608,7 @@ EXPORT_SYMBOL(drm_crtc_check_viewport);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_setcrtc(struct drm_device *dev, void *data,
                     struct drm_file *file_priv)
@@ -2709,7 +2771,7 @@ out:
  * userspace wants to make use of these capabilities.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 static int drm_mode_cursor_universal(struct drm_crtc *crtc,
                                     struct drm_mode_cursor2 *req,
@@ -2810,7 +2872,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
         * If this crtc has a universal cursor plane, call that plane's update
         * handler rather than using legacy cursor handlers.
         */
-       drm_modeset_lock_crtc(crtc);
+       drm_modeset_lock_crtc(crtc, crtc->cursor);
        if (crtc->cursor) {
                ret = drm_mode_cursor_universal(crtc, req, file_priv);
                goto out;
@@ -2857,7 +2919,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_cursor_ioctl(struct drm_device *dev,
                          void *data, struct drm_file *file_priv)
@@ -2884,12 +2946,13 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_cursor2_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
 {
        struct drm_mode_cursor2 *req = data;
+
        return drm_mode_cursor_common(dev, req, file_priv);
 }
 
@@ -2943,23 +3006,21 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  * @file_priv: drm file for the ioctl call
  *
  * Add a new FB to the specified CRTC, given a user request. This is the
- * original addfb ioclt which only supported RGB formats.
+ * original addfb ioctl which only supported RGB formats.
  *
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_addfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
 {
        struct drm_mode_fb_cmd *or = data;
        struct drm_mode_fb_cmd2 r = {};
-       struct drm_mode_config *config = &dev->mode_config;
-       struct drm_framebuffer *fb;
-       int ret = 0;
+       int ret;
 
-       /* Use new struct with format internally */
+       /* convert to new format and call new ioctl */
        r.fb_id = or->fb_id;
        r.width = or->width;
        r.height = or->height;
@@ -2967,28 +3028,13 @@ int drm_mode_addfb(struct drm_device *dev,
        r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
        r.handles[0] = or->handle;
 
-       if (!drm_core_check_feature(dev, DRIVER_MODESET))
-               return -EINVAL;
-
-       if ((config->min_width > r.width) || (r.width > config->max_width))
-               return -EINVAL;
-
-       if ((config->min_height > r.height) || (r.height > config->max_height))
-               return -EINVAL;
+       ret = drm_mode_addfb2(dev, &r, file_priv);
+       if (ret)
+               return ret;
 
-       fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
-       if (IS_ERR(fb)) {
-               DRM_DEBUG_KMS("could not create framebuffer\n");
-               return PTR_ERR(fb);
-       }
+       or->fb_id = r.fb_id;
 
-       mutex_lock(&file_priv->fbs_lock);
-       or->fb_id = fb->base.id;
-       list_add(&fb->filp_head, &file_priv->fbs);
-       DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
-       mutex_unlock(&file_priv->fbs_lock);
-
-       return ret;
+       return 0;
 }
 
 static int format_check(const struct drm_mode_fb_cmd2 *r)
@@ -3080,7 +3126,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
        num_planes = drm_format_num_planes(r->pixel_format);
 
        if (r->width == 0 || r->width % hsub) {
-               DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
+               DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
                return -EINVAL;
        }
 
@@ -3170,7 +3216,7 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_addfb2(struct drm_device *dev,
                    void *data, struct drm_file *file_priv)
@@ -3198,7 +3244,7 @@ int drm_mode_addfb2(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_rmfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
@@ -3252,7 +3298,7 @@ fail_lookup:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getfb(struct drm_device *dev,
                   void *data, struct drm_file *file_priv)
@@ -3313,7 +3359,7 @@ int drm_mode_getfb(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
@@ -3354,7 +3400,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
                        ret = -EINVAL;
                        goto out_err1;
                }
-               clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
+               clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
                if (!clips) {
                        ret = -ENOMEM;
                        goto out_err1;
@@ -3393,7 +3439,7 @@ out_err1:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 void drm_fb_release(struct drm_file *priv)
 {
@@ -3402,7 +3448,7 @@ void drm_fb_release(struct drm_file *priv)
 
        /*
         * When the file gets released that means no one else can access the fb
-        * list any more, so no need to grab fpriv->fbs_lock. And we need to to
+        * list any more, so no need to grab fpriv->fbs_lock. And we need to
         * avoid upsetting lockdep since the universal cursor code adds a
         * framebuffer while holding mutex locks.
         *
@@ -3435,6 +3481,10 @@ void drm_fb_release(struct drm_file *priv)
  * object with drm_object_attach_property. The returned property object must be
  * freed with drm_property_destroy.
  *
+ * Note that the DRM core keeps a per-device list of properties and that, if
+ * drm_mode_config_cleanup() is called, it will destroy all properties created
+ * by the driver.
+ *
  * Returns:
  * A pointer to the newly created property on success, NULL on failure.
  */
@@ -3451,7 +3501,8 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
        property->dev = dev;
 
        if (num_values) {
-               property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
+               property->values = kcalloc(num_values, sizeof(uint64_t),
+                                          GFP_KERNEL);
                if (!property->values)
                        goto fail;
        }
@@ -3462,7 +3513,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
 
        property->flags = flags;
        property->num_values = num_values;
-       INIT_LIST_HEAD(&property->enum_blob_list);
+       INIT_LIST_HEAD(&property->enum_list);
 
        if (name) {
                strncpy(property->name, name, DRM_PROP_NAME_LEN);
@@ -3611,7 +3662,7 @@ static struct drm_property *property_create_range(struct drm_device *dev,
  * object with drm_object_attach_property. The returned property object must be
  * freed with drm_property_destroy.
  *
- * Userspace is allowed to set any interger value in the (min, max) range
+ * Userspace is allowed to set any integer value in the (min, max) range
  * inclusive.
  *
  * Returns:
@@ -3684,8 +3735,8 @@ int drm_property_add_enum(struct drm_property *property, int index,
                        (value > 63))
                return -EINVAL;
 
-       if (!list_empty(&property->enum_blob_list)) {
-               list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+       if (!list_empty(&property->enum_list)) {
+               list_for_each_entry(prop_enum, &property->enum_list, head) {
                        if (prop_enum->value == value) {
                                strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
                                prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
@@ -3703,7 +3754,7 @@ int drm_property_add_enum(struct drm_property *property, int index,
        prop_enum->value = value;
 
        property->values[index] = value;
-       list_add_tail(&prop_enum->head, &property->enum_blob_list);
+       list_add_tail(&prop_enum->head, &property->enum_list);
        return 0;
 }
 EXPORT_SYMBOL(drm_property_add_enum);
@@ -3720,7 +3771,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
 {
        struct drm_property_enum *prop_enum, *pt;
 
-       list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
+       list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) {
                list_del(&prop_enum->head);
                kfree(prop_enum);
        }
@@ -3823,17 +3874,20 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
 EXPORT_SYMBOL(drm_object_property_get_value);
 
 /**
- * drm_mode_getproperty_ioctl - get the current value of a connector's property
+ * drm_mode_getproperty_ioctl - get the property metadata
  * @dev: DRM device
  * @data: ioctl data
  * @file_priv: DRM file info
  *
- * This function retrieves the current value for an connectors's property.
+ * This function retrieves the metadata for a given property, like the different
+ * possible values for an enum property or the limits for a range property.
+ *
+ * Blob properties are special
  *
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getproperty_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv)
@@ -3841,16 +3895,12 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
        struct drm_mode_get_property *out_resp = data;
        struct drm_property *property;
        int enum_count = 0;
-       int blob_count = 0;
        int value_count = 0;
        int ret = 0, i;
        int copied;
        struct drm_property_enum *prop_enum;
        struct drm_mode_property_enum __user *enum_ptr;
-       struct drm_property_blob *prop_blob;
-       uint32_t __user *blob_id_ptr;
        uint64_t __user *values_ptr;
-       uint32_t __user *blob_length_ptr;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
@@ -3864,11 +3914,8 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 
        if (drm_property_type_is(property, DRM_MODE_PROP_ENUM) ||
                        drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
-               list_for_each_entry(prop_enum, &property->enum_blob_list, head)
+               list_for_each_entry(prop_enum, &property->enum_list, head)
                        enum_count++;
-       } else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
-               list_for_each_entry(prop_blob, &property->enum_blob_list, head)
-                       blob_count++;
        }
 
        value_count = property->num_values;
@@ -3893,7 +3940,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
                if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
                        copied = 0;
                        enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
-                       list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+                       list_for_each_entry(prop_enum, &property->enum_list, head) {
 
                                if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
                                        ret = -EFAULT;
@@ -3911,28 +3958,16 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
                out_resp->count_enum_blobs = enum_count;
        }
 
-       if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
-               if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
-                       copied = 0;
-                       blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr;
-                       blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr;
-
-                       list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
-                               if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
-                                       ret = -EFAULT;
-                                       goto done;
-                               }
-
-                               if (put_user(prop_blob->length, blob_length_ptr + copied)) {
-                                       ret = -EFAULT;
-                                       goto done;
-                               }
-
-                               copied++;
-                       }
-               }
-               out_resp->count_enum_blobs = blob_count;
-       }
+       /*
+        * NOTE: The idea seems to have been to use this to read all the blob
+        * property values. But nothing ever added them to the corresponding
+        * list, userspace always used the special-purpose get_blob ioctl to
+        * read the value for a blob property. It also doesn't make a lot of
+        * sense to return values here when everything else is just metadata for
+        * the property itself.
+        */
+       if (drm_property_type_is(property, DRM_MODE_PROP_BLOB))
+               out_resp->count_enum_blobs = 0;
 done:
        drm_modeset_unlock_all(dev);
        return ret;
@@ -3986,7 +4021,7 @@ static void drm_property_destroy_blob(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_getblob_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
@@ -4008,7 +4043,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 
        if (out_resp->length == blob->length) {
                blob_ptr = (void __user *)(unsigned long)out_resp->data;
-               if (copy_to_user(blob_ptr, blob->data, blob->length)){
+               if (copy_to_user(blob_ptr, blob->data, blob->length)) {
                        ret = -EFAULT;
                        goto done;
                }
@@ -4020,6 +4055,19 @@ done:
        return ret;
 }
 
+/**
+ * drm_mode_connector_set_path_property - set tile property on connector
+ * @connector: connector to set property on.
+ * @path: path to use for property.
+ *
+ * This creates a property to expose to userspace to specify a
+ * connector path. This is mainly used for DisplayPort MST where
+ * connectors have a topology and we want to allow userspace to give
+ * them more meaningful names.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
 int drm_mode_connector_set_path_property(struct drm_connector *connector,
                                         const char *path)
 {
@@ -4048,7 +4096,7 @@ EXPORT_SYMBOL(drm_mode_connector_set_path_property);
  * connector's edid property.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_connector_update_edid_property(struct drm_connector *connector,
                                            const struct edid *edid)
@@ -4097,6 +4145,7 @@ static bool drm_property_change_is_valid(struct drm_property *property,
                return true;
        } else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
                int64_t svalue = U642I64(value);
+
                if (svalue < U642I64(property->values[0]) ||
                                svalue > U642I64(property->values[1]))
                        return false;
@@ -4104,6 +4153,7 @@ static bool drm_property_change_is_valid(struct drm_property *property,
        } else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
                int i;
                uint64_t valid_mask = 0;
+
                for (i = 0; i < property->num_values; i++)
                        valid_mask |= (1ULL << property->values[i]);
                return !(value & ~valid_mask);
@@ -4112,6 +4162,7 @@ static bool drm_property_change_is_valid(struct drm_property *property,
                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;
@@ -4145,7 +4196,7 @@ static bool drm_property_change_is_valid(struct drm_property *property,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
                                       void *data, struct drm_file *file_priv)
@@ -4228,7 +4279,7 @@ int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
 EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
 /**
- * drm_mode_getproperty_ioctl - get the current value of a object's property
+ * drm_mode_obj_get_properties_ioctl - get the current value of a object's property
  * @dev: DRM device
  * @data: ioctl data
  * @file_priv: DRM file info
@@ -4240,7 +4291,7 @@ EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
                                      struct drm_file *file_priv)
@@ -4312,7 +4363,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
                                    struct drm_file *file_priv)
@@ -4384,7 +4435,7 @@ out:
  * possible_clones and possible_crtcs bitmasks.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_connector_attach_encoder(struct drm_connector *connector,
                                      struct drm_encoder *encoder)
@@ -4411,14 +4462,15 @@ EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
  * fixed gamma table size.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
                                 int gamma_size)
 {
        crtc->gamma_size = gamma_size;
 
-       crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
+       crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
+                                   GFP_KERNEL);
        if (!crtc->gamma_store) {
                crtc->gamma_size = 0;
                return -ENOMEM;
@@ -4440,7 +4492,7 @@ EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4512,7 +4564,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_gamma_get_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4578,7 +4630,7 @@ out:
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_page_flip_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4601,7 +4653,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        if (!crtc)
                return -ENOENT;
 
-       drm_modeset_lock_crtc(crtc);
+       drm_modeset_lock_crtc(crtc, crtc->primary);
        if (crtc->primary->fb == NULL) {
                /* The framebuffer is currently unbound, presumably
                 * due to a hotplug event, that userspace has not
@@ -4744,7 +4796,7 @@ EXPORT_SYMBOL(drm_mode_config_reset);
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_create_dumb_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv)
@@ -4771,6 +4823,16 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
        if (PAGE_ALIGN(size) == 0)
                return -EINVAL;
 
+       /*
+        * handle, pitch and size are output parameters. Zero them out to
+        * prevent drivers from accidentally using uninitialized data. Since
+        * not all existing userspace is clearing these fields properly we
+        * cannot reject IOCTL with garbage in them.
+        */
+       args->handle = 0;
+       args->pitch = 0;
+       args->size = 0;
+
        return dev->driver->dumb_create(file_priv, dev, args);
 }
 
@@ -4786,7 +4848,7 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
@@ -4813,7 +4875,7 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
  * Called by the user via ioctl.
  *
  * Returns:
- * Zero on success, errno on failure.
+ * Zero on success, negative errno on failure.
  */
 int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
                                void *data, struct drm_file *file_priv)