From ecb7e16bf187bc369cf6a5cd108582c01329980d Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 1 Dec 2014 15:40:09 -0800 Subject: drm: add helper to get crtc timings (v5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to get hdisplay and vdisplay in a few places so create a helper to make our job easier. Note that drm_crtc_check_viewport() and intel_modeset_pipe_config() were previously making adjustments for doublescan modes and vscan > 1 modes, which was incorrect. Using our new helper fixes this mistake. v2 (by Matt): Use new stereo doubling function (suggested by Ville) v3 (by Matt): - Add missing kerneldoc (Daniel) - Use drm_mode_copy() (Jani) v4 (by Matt): - Drop stereo doubling function again; add 'stereo only' flag to drm_mode_set_crtcinfo() instead (Ville) v5 (by Matt): - Note behavioral change in drm_crtc_check_viewport() and intel_modeset_pipe_config(). (Ander) - Describe new adjustment flags in drm_mode_set_crtcinfo()'s kerneldoc. (Ander) Cc: dri-devel@lists.freedesktop.org Suggested-by: Ville Syrjälä Signed-off-by: Gustavo Padovan Signed-off-by: Matt Roper Acked-by: Dave Airlie Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index de79283eaea7..2985e3ff364f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2549,6 +2549,27 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) } EXPORT_SYMBOL(drm_mode_set_config_internal); +/** + * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode + * @mode: mode to query + * @hdisplay: hdisplay value to fill in + * @vdisplay: vdisplay value to fill in + * + * The vdisplay value will be doubled if the specified mode is a stereo mode of + * the appropriate layout. + */ +void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, + int *hdisplay, int *vdisplay) +{ + struct drm_display_mode adjusted; + + drm_mode_copy(&adjusted, mode); + drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY); + *hdisplay = adjusted.crtc_hdisplay; + *vdisplay = adjusted.crtc_vdisplay; +} +EXPORT_SYMBOL(drm_crtc_get_hv_timing); + /** * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the * CRTC viewport @@ -2566,16 +2587,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, { int hdisplay, vdisplay; - hdisplay = mode->hdisplay; - vdisplay = mode->vdisplay; - - if (drm_mode_is_stereo(mode)) { - struct drm_display_mode adjusted = *mode; - - drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE); - hdisplay = adjusted.crtc_hdisplay; - vdisplay = adjusted.crtc_vdisplay; - } + drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); if (crtc->invert_dimensions) swap(hdisplay, vdisplay); -- cgit v1.2.3 From 4dfd909f92d623d79a23985526314bb31bdd110a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:34 +0100 Subject: drm: Miscellaneous checkpatch whitespace cleanups A couple of whitespace changes required to silent various errors and warnings flagged by checkpatch. checkpatch requires that the opening brace be on the same line as a variable declaration. Furthermore an empty line is required after a block of variable declarations. Trailing whitespace as well as using spaces before tabs is considered an error or warning, respectively. Finally, the closing parenthesis of an if condition and the opening brace of the conditional block should be separated by a space. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 42 ++++++++++++++++++++---------------------- drivers/gpu/drm/drm_irq.c | 3 ++- 2 files changed, 22 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 632e6eaf4c74..76aa8fb787dc 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -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" }, @@ -1137,6 +1130,7 @@ 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); @@ -2519,7 +2513,7 @@ 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, negative errno on failure. */ @@ -2958,6 +2952,7 @@ 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); } @@ -4047,7 +4042,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; } @@ -4149,6 +4144,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; @@ -4156,6 +4152,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); @@ -4164,6 +4161,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; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f5a5f18efa5b..fadcd16d2300 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -778,7 +778,7 @@ static struct timeval get_drm_timestamp(void) /** * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent - * vblank interval + * vblank interval * @dev: DRM device * @crtc: which CRTC's vblank timestamp to retrieve * @tvblank: Pointer to target struct timeval which should receive the timestamp @@ -910,6 +910,7 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, { struct timeval now; unsigned int seq; + if (crtc >= 0) { seq = drm_vblank_count_and_time(dev, crtc, &now); } else { -- cgit v1.2.3 From bd3f0ff98a849e04dc2c0236f32cc75b8c8630db Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:35 +0100 Subject: drm: Prefer kcalloc() over kzalloc() with multiply Fixes a couple of checkpatch warnings regarding the use of kzalloc() with a multiplication. kcalloc() is the preferred API. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 76aa8fb787dc..45e17df41f22 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1583,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; @@ -3400,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; @@ -3501,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; } @@ -4468,7 +4469,8 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, { 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; -- cgit v1.2.3 From 2f6c538924108fbffb72a0696f28537b364080fa Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:36 +0100 Subject: drm: Prefer kmalloc_array() over kmalloc() with multiply Fixes a couple of checkpatch warnings regarding the use of kmalloc() with a multiplication. kmalloc_array() is the preferred API. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 45e17df41f22..0d3a4105f4e8 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1174,8 +1174,8 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, plane->base.properties = &plane->properties; plane->dev = dev; plane->funcs = funcs; - plane->format_types = kmalloc(sizeof(uint32_t) * format_count, - GFP_KERNEL); + plane->format_types = kmalloc_array(format_count, sizeof(uint32_t), + GFP_KERNEL); if (!plane->format_types) { DRM_DEBUG_KMS("out of memory when allocating plane\n"); drm_mode_object_put(dev, &plane->base); @@ -2705,9 +2705,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } - connector_set = kmalloc(crtc_req->count_connectors * - sizeof(struct drm_connector *), - GFP_KERNEL); + connector_set = kmalloc_array(crtc_req->count_connectors, + sizeof(struct drm_connector *), + GFP_KERNEL); if (!connector_set) { ret = -ENOMEM; goto out; -- cgit v1.2.3 From 0cc0b223e7c9b4642c86d46f20d3d4a4a89bede3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:37 +0100 Subject: drm: Do not assign in if condition checkpatch requires the assignment and the check to be separate statements. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0d3a4105f4e8..e8036fd38aee 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1613,7 +1613,8 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_bridge *bridge; int ret; - if ((ret = drm_mode_group_init(dev, group))) + ret = drm_mode_group_init(dev, group); + if (ret) return ret; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) -- cgit v1.2.3 From 01073b0846c7c13438ef9b4d62e0747aed2db15d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:38 +0100 Subject: drm: Remove unneeded braces for single statement blocks Single statement blocks don't need to be enclosed in a pair of braces. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e8036fd38aee..fa1b1a5b8330 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2030,11 +2030,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, props_count = connector->properties.count; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] != 0) { + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) + if (connector->encoder_ids[i] != 0) encoders_count++; - } - } if (out_resp->count_modes == 0) { connector->funcs->fill_modes(connector, -- cgit v1.2.3 From 2ca651d15aff0f613d11913e8a10e3b86b3dc44a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:39 +0100 Subject: drm: Remove useless else block All prior conditional blocks return from the function, so the else block can be at the top level of the function. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fa1b1a5b8330..4f4fcd37f110 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4135,6 +4135,8 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property); static bool drm_property_change_is_valid(struct drm_property *property, uint64_t value) { + int i; + if (property->flags & DRM_MODE_PROP_IMMUTABLE) return false; @@ -4150,7 +4152,6 @@ static bool drm_property_change_is_valid(struct drm_property *property, return false; return true; } 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++) @@ -4174,13 +4175,12 @@ static bool drm_property_change_is_valid(struct drm_property *property, */ obj = _object_find(property->dev, value, property->values[0]); return obj != 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++) + if (property->values[i] == value) + return true; + return false; } /** -- cgit v1.2.3 From f76511b97237f159b6b9a951a4f7fdd773d9698d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Dec 2014 13:03:40 +0100 Subject: drm: Prefer sizeof(type) over sizeof type sizeof(type) is the variant used most commonly and required by checkpatch. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 12 ++++++------ drivers/gpu/drm/drm_irq.c | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 4f4fcd37f110..6700ebafef16 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4684,23 +4684,23 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { ret = -ENOMEM; spin_lock_irqsave(&dev->event_lock, flags); - if (file_priv->event_space < sizeof e->event) { + if (file_priv->event_space < sizeof(e->event)) { spin_unlock_irqrestore(&dev->event_lock, flags); goto out; } - file_priv->event_space -= sizeof e->event; + file_priv->event_space -= sizeof(e->event); spin_unlock_irqrestore(&dev->event_lock, flags); - e = kzalloc(sizeof *e, GFP_KERNEL); + e = kzalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) { spin_lock_irqsave(&dev->event_lock, flags); - file_priv->event_space += sizeof e->event; + file_priv->event_space += sizeof(e->event); spin_unlock_irqrestore(&dev->event_lock, flags); goto out; } e->event.base.type = DRM_EVENT_FLIP_COMPLETE; - e->event.base.length = sizeof e->event; + e->event.base.length = sizeof(e->event); e->event.user_data = page_flip->user_data; e->base.event = &e->event.base; e->base.file_priv = file_priv; @@ -4713,7 +4713,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { spin_lock_irqsave(&dev->event_lock, flags); - file_priv->event_space += sizeof e->event; + file_priv->event_space += sizeof(e->event); spin_unlock_irqrestore(&dev->event_lock, flags); kfree(e); } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index fadcd16d2300..920cdb91e9d0 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1383,7 +1383,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, unsigned int seq; int ret; - e = kzalloc(sizeof *e, GFP_KERNEL); + e = kzalloc(sizeof(*e), GFP_KERNEL); if (e == NULL) { ret = -ENOMEM; goto err_put; @@ -1392,7 +1392,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->pipe = pipe; e->base.pid = current->pid; e->event.base.type = DRM_EVENT_VBLANK; - e->event.base.length = sizeof e->event; + e->event.base.length = sizeof(e->event); e->event.user_data = vblwait->request.signal; e->base.event = &e->event.base; e->base.file_priv = file_priv; @@ -1412,12 +1412,12 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, goto err_unlock; } - if (file_priv->event_space < sizeof e->event) { + if (file_priv->event_space < sizeof(e->event)) { ret = -EBUSY; goto err_unlock; } - file_priv->event_space -= sizeof e->event; + file_priv->event_space -= sizeof(e->event); seq = drm_vblank_count_and_time(dev, pipe, &now); if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && -- cgit v1.2.3 From 23e1ce89af5404c7a35dbd008ca85fb6adb16aad Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Dec 2014 13:56:24 +0200 Subject: drm: Do basic sanity checks for user modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently userspace is allowed to pass in basiclly any kind of garbage to setcrtc. Try to catch the cases where the timings make no sense by passing the mode through drm_mode_validate_basic(). One concern here is that we now start to block some modes that have worked in the past. It's at least possible with when using i915 with LVDS/eDP. Previously we've just ignored everything but hdisplay/vdisplay from the user mode and just overwritten the rest with the panel fixed mode. So if someone has been passing a mode with just those populated that would now stop working. If that is a real problem, we can't add these checks to the core code and each driver would have to have its own sanity checks. So fingers crossed... Signed-off-by: Ville Syrjälä Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6700ebafef16..e3140c190556 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2673,6 +2673,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, 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, -- cgit v1.2.3 From 3843e71f9882c9e2e965cf025f3a7d4de19ce823 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 16 Dec 2014 18:05:29 -0500 Subject: drm: allow property validation for refcnted props We can already have object properties, which technically can be fb's. Switch the property validation logic over to a get/put style interface so it can take a ref to refcnt'd objects, and then drop that ref after the driver has a chance to take it's own ref. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 58 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5213da499d39..5ee4b8806aca 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4193,12 +4193,22 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, } 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). + */ +static bool drm_property_change_valid_get(struct drm_property *property, + uint64_t value, struct drm_mode_object **ref) { 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; @@ -4219,19 +4229,23 @@ static bool drm_property_change_is_valid(struct drm_property *property, /* 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++) @@ -4241,6 +4255,18 @@ static bool drm_property_change_is_valid(struct drm_property *property, } } +static 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 @@ -4429,8 +4455,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 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; @@ -4460,7 +4486,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, } 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) { @@ -4477,6 +4503,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, break; } + drm_property_change_valid_put(property, ref); + out: drm_modeset_unlock_all(dev); return ret; -- cgit v1.2.3 From b17cd757a3f61e4519b70b4673f0467ec0153a10 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 16 Dec 2014 18:05:30 -0500 Subject: drm: store property instead of id in obj attachment Keep property pointer, instead of id, in per mode-object attachments. This will simplify things in later patches. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 17 ++++++++--------- include/drm/drm_crtc.h | 7 ++++++- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5ee4b8806aca..2780a088051e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2105,12 +2105,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, 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)) { + struct drm_property *prop = connector->properties.properties[i]; + if (put_user(prop->base.id, prop_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(connector->properties.values[i], prop_values + copied)) { ret = -EFAULT; @@ -3822,7 +3821,7 @@ void drm_object_attach_property(struct drm_mode_object *obj, return; } - obj->properties->ids[count] = property->base.id; + obj->properties->properties[count] = property; obj->properties->values[count] = init_val; obj->properties->count++; } @@ -3847,7 +3846,7 @@ int drm_object_property_set_value(struct drm_mode_object *obj, 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,7 +3876,7 @@ int drm_object_property_get_value(struct drm_mode_object *obj, int i; 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; } @@ -4413,8 +4412,8 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 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)) { + struct drm_property *prop = obj->properties->properties[i]; + if (put_user(prop->base.id, props_ptr + copied)) { ret = -EFAULT; goto out; } @@ -4472,7 +4471,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 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) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index fd8139ca629a..265f90afcac4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -64,7 +64,12 @@ struct drm_mode_object { #define DRM_OBJECT_MAX_PROPERTY 24 struct drm_object_properties { int count; - uint32_t ids[DRM_OBJECT_MAX_PROPERTY]; + /* 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]; uint64_t values[DRM_OBJECT_MAX_PROPERTY]; }; -- cgit v1.2.3 From 22b8b13b6f436ffbb6e540f5f8039b1084a72794 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 16 Dec 2014 18:05:31 -0500 Subject: drm: get rid of direct property value access For atomic drivers, we won't use the values array but instead shunt things off to obj->atomic_get_property(). So to simplify things make all read/write of properties values go through the accessors. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 19 +++++++++++++++---- include/drm/drm_crtc.h | 3 +++ 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2780a088051e..481bb2598b62 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2106,12 +2106,17 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); for (i = 0; i < connector->properties.count; i++) { struct drm_property *prop = connector->properties.properties[i]; + uint64_t val; + + ret = drm_object_property_get_value(&connector->base, prop, &val); + if (ret) + goto out; + if (put_user(prop->base.id, prop_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(connector->properties.values[i], - prop_values + copied)) { + if (put_user(val, prop_values + copied)) { ret = -EFAULT; goto out; } @@ -4413,12 +4418,18 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, (arg->prop_values_ptr); for (i = 0; i < props_count; i++) { struct drm_property *prop = obj->properties->properties[i]; + uint64_t val; + + ret = drm_object_property_get_value(obj, prop, &val); + if (ret) + goto out; + if (put_user(prop->base.id, props_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(obj->properties->values[i], - prop_values_ptr + copied)) { + + if (put_user(val, prop_values_ptr + copied)) { ret = -EFAULT; goto out; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 265f90afcac4..f7c0b7bb9d5f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -70,6 +70,9 @@ struct drm_object_properties { * 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]; }; -- cgit v1.2.3 From ccfc08655d5fd5076828f45fb09194c070f2f63a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:48 -0500 Subject: drm: tweak getconnector locking We need to hold connection_mutex as we read the properties. Easiest thing is just widen the scope where connection_mutex is held. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 303c9918a2d5..2031ead208b1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2031,6 +2031,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, 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) { @@ -2062,14 +2063,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, 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 @@ -2135,6 +2133,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, out_resp->count_encoders = encoders_count; out: + drm_modeset_unlock(&dev->mode_config.connection_mutex); mutex_unlock(&dev->mode_config.mutex); return ret; -- cgit v1.2.3 From 95cbf110756c21397946ded181cc5ea4ab568c11 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:49 -0500 Subject: drm: refactor getproperties/getconnector Both need to iterate a mode objects properties. Split that out into a helper shared by both ioctl handlers, since this is going to become more complicated when we add atomic properties (which will need filtering from legacy userspace). Signed-off-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 105 ++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 63 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 2031ead208b1..f5f34d0d7c20 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1991,6 +1991,38 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne return connector->encoder; } +/* helper for getconnector and getproperties ioctls */ +static int get_properties(struct drm_mode_object *obj, + uint32_t __user *prop_ptr, uint64_t __user *prop_values, + uint32_t *arg_count_props) +{ + int props_count = obj->properties->count; + int i, ret, copied = 0; + + if ((*arg_count_props >= props_count) && props_count) { + copied = 0; + for (i = 0; i < props_count; i++) { + struct drm_property *prop = obj->properties->properties[i]; + uint64_t val; + + 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 +2044,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, 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)) @@ -2039,8 +2068,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, goto out; } - props_count = connector->properties.count; - for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) if (connector->encoder_ids[i] != 0) encoders_count++; @@ -2091,30 +2118,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, } 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++) { - struct drm_property *prop = connector->properties.properties[i]; - uint64_t val; - - ret = drm_object_property_get_value(&connector->base, prop, &val); - if (ret) - goto out; - - if (put_user(prop->base.id, prop_ptr + copied)) { - ret = -EFAULT; - goto out; - } - if (put_user(val, prop_values + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - out_resp->count_props = props_count; + ret = get_properties(&connector->base, + (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; @@ -4388,11 +4397,6 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, 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; @@ -4409,36 +4413,11 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, goto out; } - props_count = obj->properties->count; - - /* 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++) { - struct drm_property *prop = obj->properties->properties[i]; - uint64_t val; - - ret = drm_object_property_get_value(obj, prop, &val); - if (ret) - goto out; + ret = get_properties(obj, + (uint32_t __user *)(unsigned long)(arg->props_ptr), + (uint64_t __user *)(unsigned long)(arg->prop_values_ptr), + &arg->count_props); - if (put_user(prop->base.id, props_ptr + copied)) { - ret = -EFAULT; - goto out; - } - - if (put_user(val, prop_values_ptr + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - arg->count_props = props_count; out: drm_modeset_unlock_all(dev); return ret; -- cgit v1.2.3 From 88a48e297b3a3bac6022c03babfb038f1a886cea Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:50 -0500 Subject: drm: add atomic properties Once a driver is using atomic helpers for modeset, the next step is to switch over to atomic properties. To do this, make sure that any modeset objects have their ->atomic_{get,set}_property() vfuncs suitably populated if they have custom properties (you did already remember to plug in atomic-helper func for the legacy ->set_property() vfuncs, right?), and then set DRIVER_ATOMIC bit in driver_features flag. A new cap is introduced, DRM_CLIENT_CAP_ATOMIC, for the purposes of shielding legacy userspace from atomic properties. Mostly for the benefit of legacy DDX drivers that do silly things like getting/setting each property at startup (since some of the new atomic properties will be able to trigger modeset). Signed-off-by: Rob Clark [danvet: Squash in fixup patch to check for DRM_MODE_PROP_ATOMIC instaed of the CAP define when filtering properties. Reported by Tvrtko Uruslin, acked by Rob.] Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 8 ++++++++ drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 31 ++++++++++++++++++++++------- drivers/gpu/drm/drm_drv.c | 4 ++++ drivers/gpu/drm/drm_ioctl.c | 10 ++++++++++ include/drm/drmP.h | 4 ++++ include/drm/drm_atomic.h | 3 +++ include/drm/drm_crtc.h | 2 +- include/uapi/drm/drm.h | 7 +++++++ include/uapi/drm/drm_mode.h | 7 +++++++ 10 files changed, 113 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 4b592ffbafee..7fa4f9873cf7 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -239,6 +239,14 @@ Driver supports dedicated render nodes. + + DRIVER_ATOMIC + + 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. + + diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 9c4e149a61e2..ce3c681d60f8 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -520,6 +520,51 @@ int drm_atomic_connector_get_property(struct drm_connector *connector, } EXPORT_SYMBOL(drm_atomic_connector_get_property); +/** + * drm_atomic_get_property - helper to read atomic property + * @obj: drm mode object whose property to read + * @property: the property to read + * @val: the read value, returned by reference + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_atomic_get_property(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val) +{ + struct drm_device *dev = property->dev; + int ret; + + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: { + struct drm_connector *connector = obj_to_connector(obj); + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + ret = drm_atomic_connector_get_property(connector, + connector->state, property, val); + break; + } + case DRM_MODE_OBJECT_CRTC: { + struct drm_crtc *crtc = obj_to_crtc(obj); + WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); + ret = drm_atomic_crtc_get_property(crtc, + crtc->state, property, val); + break; + } + case DRM_MODE_OBJECT_PLANE: { + struct drm_plane *plane = obj_to_plane(obj); + WARN_ON(!drm_modeset_is_locked(&plane->mutex)); + ret = drm_atomic_plane_get_property(plane, + plane->state, property, val); + break; + } + default: + ret = -EINVAL; + break; + } + + return ret; +} + /** * drm_atomic_set_crtc_for_plane - set crtc for plane * @plane_state: the plane whose incoming state to update diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f5f34d0d7c20..3bac877228fa 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" #include "drm_internal.h" @@ -1992,19 +1993,25 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne } /* helper for getconnector and getproperties ioctls */ -static int get_properties(struct drm_mode_object *obj, +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 = obj->properties->count; - int i, ret, copied = 0; + 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) { - copied = 0; - for (i = 0; i < props_count; i++) { + 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; @@ -2118,7 +2125,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, } out_resp->count_modes = mode_count; - ret = get_properties(&connector->base, + 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); @@ -3832,6 +3839,8 @@ void drm_object_attach_property(struct drm_mode_object *obj, 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); @@ -3883,6 +3892,14 @@ int drm_object_property_get_value(struct drm_mode_object *obj, { 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->properties[i] == property) { *val = obj->properties->values[i]; @@ -4413,7 +4430,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, goto out; } - ret = get_properties(obj, + 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); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 4f41377b0b80..d51213464672 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -40,15 +40,19 @@ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); +bool drm_atomic = 0; + MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output"); +MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API"); MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); module_param_named(debug, drm_debug, int, 0600); +module_param_named_unsafe(atomic, drm_atomic, bool, 0600); static DEFINE_SPINLOCK(drm_minor_lock); static struct idr drm_minors_idr; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 00587a1e3c83..adc822312f6c 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -345,6 +345,16 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; file_priv->universal_planes = req->value; break; + case DRM_CLIENT_CAP_ATOMIC: + /* for now, hide behind experimental drm.atomic moduleparam */ + if (!drm_atomic) + return -EINVAL; + if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) + return -EINVAL; + if (req->value > 1) + return -EINVAL; + file_priv->atomic = req->value; + break; default: return -EINVAL; } diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 8ba35c622e22..0f7115e988a0 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -143,6 +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 @@ 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; @@ -950,6 +953,7 @@ extern void drm_master_put(struct drm_master **master); 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 --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index d41233ccbc9e..231fb485abb3 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -63,6 +63,9 @@ int drm_atomic_connector_get_property(struct drm_connector *connector, const struct drm_connector_state *state, struct drm_property *property, uint64_t *val); +int drm_atomic_get_property(struct drm_mode_object *obj, + struct drm_property *property, uint64_t *val); + int __must_check drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, struct drm_crtc *crtc); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index e1f34694fcff..b5ab673add29 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -63,7 +63,7 @@ struct drm_mode_object { #define DRM_OBJECT_MAX_PROPERTY 24 struct drm_object_properties { - int count; + 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 diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index b0b855613641..f7b2baf7ecb2 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -654,6 +654,13 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 +/** + * DRM_CLIENT_CAP_ATOMIC + * + * If set to 1, the DRM core will expose atomic properties to userspace + */ +#define DRM_CLIENT_CAP_ATOMIC 3 + /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index aae71cb32123..b8f9c0f2e7fe 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -272,6 +272,13 @@ struct drm_mode_get_connector { #define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) #define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2) +/* the PROP_ATOMIC flag is used to hide properties from userspace that + * is not aware of atomic properties. This is mostly to work around + * older userspace (DDX drivers) that read/write each prop they find, + * witout being aware that this could be triggering a lengthy modeset. + */ +#define DRM_MODE_PROP_ATOMIC 0x80000000 + struct drm_mode_property_enum { __u64 value; char name[DRM_PROP_NAME_LEN]; -- cgit v1.2.3 From 356af0e154467eb6844f25631a11940b462deca0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:52 -0500 Subject: drm: small property creation cleanup Getting ready to add a lot more standard properties for atomic. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter [danvet: Realign function paramaters where the lines shrunk massively.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3bac877228fa..f33863a40d42 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1325,33 +1325,40 @@ EXPORT_SYMBOL(drm_plane_force_disable); static int drm_mode_create_standard_connector_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; + + 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; + + 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; return 0; } -- cgit v1.2.3 From 6b4959f43a04e12d39c5700607727f2cbcfeac31 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:53 -0500 Subject: drm/atomic: atomic plane properties Expose the core plane state as properties, so they can be updated via atomic ioctl. v2: atomic property flag Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 74 ++++++++++++++++++++++++++++- drivers/gpu/drm/drm_atomic.c | 69 +++++++++++++++++++++++++-- drivers/gpu/drm/drm_crtc.c | 103 +++++++++++++++++++++++++++++++++-------- include/drm/drm_crtc.h | 10 ++++ 4 files changed, 230 insertions(+), 26 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 7fa4f9873cf7..8d8dc7124bb5 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2572,7 +2572,7 @@ void intel_crt_init(struct drm_device *dev) Description/Restrictions - DRM + DRM Generic “EDID” BLOB | IMMUTABLE @@ -2602,7 +2602,7 @@ void intel_crt_init(struct drm_device *dev) Contains tiling information for a connector. - Plane + Plane “type” ENUM | IMMUTABLE { "Overlay", "Primary", "Cursor" } @@ -2610,6 +2610,76 @@ void intel_crt_init(struct drm_device *dev) Plane type + “SRC_X” + RANGE + Min=0, Max=UINT_MAX + Plane + Scanout source x coordinate in 16.16 fixed point (atomic) + + + “SRC_Y” + RANGE + Min=0, Max=UINT_MAX + Plane + Scanout source y coordinate in 16.16 fixed point (atomic) + + + “SRC_W” + RANGE + Min=0, Max=UINT_MAX + Plane + Scanout source width in 16.16 fixed point (atomic) + + + “SRC_H” + RANGE + Min=0, Max=UINT_MAX + Plane + Scanout source height in 16.16 fixed point (atomic) + + + “CRTC_X” + SIGNED_RANGE + Min=INT_MIN, Max=INT_MAX + Plane + Scanout CRTC (destination) x coordinate (atomic) + + + “CRTC_Y” + SIGNED_RANGE + Min=INT_MIN, Max=INT_MAX + Plane + Scanout CRTC (destination) y coordinate (atomic) + + + “CRTC_W” + RANGE + Min=0, Max=UINT_MAX + Plane + Scanout CRTC (destination) width (atomic) + + + “CRTC_H” + RANGE + Min=0, Max=UINT_MAX + Plane + Scanout CRTC (destination) height (atomic) + + + “FB_ID” + OBJECT + DRM_MODE_OBJECT_FB + Plane + Scanout framebuffer (atomic) + + + “CRTC_ID” + OBJECT + DRM_MODE_OBJECT_CRTC + Plane + CRTC that plane is attached to (atomic) + + DVI-I “subconnector” ENUM diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1c472b1baeb8..131d47f6f7a2 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -366,9 +366,41 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val) { - if (plane->funcs->atomic_set_property) - return plane->funcs->atomic_set_property(plane, state, property, val); - return -EINVAL; + struct drm_device *dev = plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_fb_id) { + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val); + drm_atomic_set_fb_for_plane(state, fb); + if (fb) + drm_framebuffer_unreference(fb); + } else if (property == config->prop_crtc_id) { + struct drm_crtc *crtc = drm_crtc_find(dev, val); + return drm_atomic_set_crtc_for_plane(state, crtc); + } else if (property == config->prop_crtc_x) { + state->crtc_x = U642I64(val); + } else if (property == config->prop_crtc_y) { + state->crtc_y = U642I64(val); + } else if (property == config->prop_crtc_w) { + state->crtc_w = val; + } else if (property == config->prop_crtc_h) { + state->crtc_h = val; + } else if (property == config->prop_src_x) { + state->src_x = val; + } else if (property == config->prop_src_y) { + state->src_y = val; + } else if (property == config->prop_src_w) { + state->src_w = val; + } else if (property == config->prop_src_h) { + state->src_h = val; + } else if (plane->funcs->atomic_set_property) { + return plane->funcs->atomic_set_property(plane, state, + property, val); + } else { + return -EINVAL; + } + + return 0; } EXPORT_SYMBOL(drm_atomic_plane_set_property); @@ -392,9 +424,36 @@ int drm_atomic_plane_get_property(struct drm_plane *plane, const struct drm_plane_state *state, struct drm_property *property, uint64_t *val) { - if (plane->funcs->atomic_get_property) + struct drm_device *dev = plane->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_fb_id) { + *val = (state->fb) ? state->fb->base.id : 0; + } else if (property == config->prop_crtc_id) { + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->prop_crtc_x) { + *val = I642U64(state->crtc_x); + } else if (property == config->prop_crtc_y) { + *val = I642U64(state->crtc_y); + } else if (property == config->prop_crtc_w) { + *val = state->crtc_w; + } else if (property == config->prop_crtc_h) { + *val = state->crtc_h; + } else if (property == config->prop_src_x) { + *val = state->src_x; + } else if (property == config->prop_src_y) { + *val = state->src_y; + } else if (property == config->prop_src_w) { + *val = state->src_w; + } else if (property == config->prop_src_h) { + *val = state->src_h; + } else if (plane->funcs->atomic_get_property) { return plane->funcs->atomic_get_property(plane, state, property, val); - return -EINVAL; + } else { + return -EINVAL; + } + + return 0; } EXPORT_SYMBOL(drm_atomic_plane_get_property); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f33863a40d42..46fa0945b53e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1169,6 +1169,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, 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); @@ -1193,15 +1194,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *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); @@ -1323,7 +1337,7 @@ void drm_plane_force_disable(struct drm_plane *plane) } 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 *prop; @@ -1360,20 +1374,72 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.tile_property = prop; - return 0; -} - -static int drm_mode_create_standard_plane_properties(struct drm_device *dev) -{ - struct drm_property *type; - - /* - * 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; } @@ -5264,8 +5330,7 @@ void drm_mode_config_init(struct drm_device *dev) 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 */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b5ab673add29..fc4767fa723b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1099,6 +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; -- cgit v1.2.3 From ae16c597b61ae4613b13a0c3fac302e8d8827ac7 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:54 -0500 Subject: drm/atomic: atomic connector properties Expose the core connector state as properties so it can be updated via atomic ioctl. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 11 +++++++++-- drivers/gpu/drm/drm_atomic.c | 9 +++++++-- drivers/gpu/drm/drm_crtc.c | 13 +++++++++---- 3 files changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 8d8dc7124bb5..2f4a29906425 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -2572,8 +2572,8 @@ void intel_crt_init(struct drm_device *dev) Description/Restrictions - DRM - Generic + DRM + Connector “EDID” BLOB | IMMUTABLE 0 @@ -2602,6 +2602,13 @@ void intel_crt_init(struct drm_device *dev) Contains tiling information for a connector. + “CRTC_ID” + OBJECT + DRM_MODE_OBJECT_CRTC + Connector + CRTC that connector is attached to (atomic) + + Plane “type” ENUM | IMMUTABLE diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 131d47f6f7a2..57cc68177f09 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -627,7 +627,10 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct drm_mode_config *config = &dev->mode_config; - if (property == config->dpms_property) { + if (property == config->prop_crtc_id) { + struct drm_crtc *crtc = drm_crtc_find(dev, val); + return drm_atomic_set_crtc_for_connector(state, crtc); + } else if (property == config->dpms_property) { /* setting DPMS property requires special handling, which * is done in legacy setprop path for us. Disallow (for * now?) atomic writes to DPMS property: @@ -665,7 +668,9 @@ int drm_atomic_connector_get_property(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct drm_mode_config *config = &dev->mode_config; - if (property == config->dpms_property) { + if (property == config->prop_crtc_id) { + *val = (state->crtc) ? state->crtc->base.id : 0; + } else if (property == config->dpms_property) { *val = connector->dpms; } else if (connector->funcs->atomic_get_property) { return connector->funcs->atomic_get_property(connector, diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 46fa0945b53e..3cb1fa09ac9e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -831,6 +831,7 @@ int drm_connector_init(struct drm_device *dev, 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; @@ -869,16 +870,20 @@ int drm_connector_init(struct drm_device *dev, /* 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; -- cgit v1.2.3 From d34f20d6e2f21bd3531b969dc40913181a8ae31a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 18 Dec 2014 16:01:56 -0500 Subject: drm: Atomic modeset ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The atomic modeset ioctl can be used to push any number of new values for object properties. The driver can then check the full device configuration as single unit, and try to apply the changes atomically. The ioctl simply takes a list of object IDs and property IDs and their values. Originally based on a patch from Ville Syrjälä, although it has mutated (mutilated?) enough since then that you probably shouldn't blame it on him ;-) The atomic support is hidden behind the DRM_CLIENT_CAP_ATOMIC cap (to protect legacy userspace) and drm.atomic module param (for now). v2: Check for file_priv->atomic to make sure we only allow userspace in-the-know to use atomic. Signed-off-by: Rob Clark Reviewed-by: Sean Paul Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 331 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 4 +- drivers/gpu/drm/drm_ioctl.c | 1 + include/drm/drm_crtc.h | 10 +- include/uapi/drm/drm.h | 1 + include/uapi/drm/drm_mode.h | 23 +++ 6 files changed, 366 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 57cc68177f09..67f64bd1058f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -56,6 +56,11 @@ drm_atomic_state_alloc(struct drm_device *dev) if (!state) return NULL; + /* TODO legacy paths should maybe do a better job about + * setting this appropriately? + */ + state->allow_modeset = true; + state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector); state->crtcs = kcalloc(dev->mode_config.num_crtc, @@ -1003,6 +1008,22 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (config->funcs->atomic_check) ret = config->funcs->atomic_check(state->dev, state); + if (!state->allow_modeset) { + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc *crtc = state->crtcs[i]; + struct drm_crtc_state *crtc_state = state->crtc_states[i]; + + if (!crtc) + continue; + + if (crtc_state->mode_changed) { + DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", + crtc->base.id); + return -EINVAL; + } + } + } + return ret; } EXPORT_SYMBOL(drm_atomic_check_only); @@ -1068,3 +1089,313 @@ int drm_atomic_async_commit(struct drm_atomic_state *state) return config->funcs->atomic_commit(state->dev, state, true); } EXPORT_SYMBOL(drm_atomic_async_commit); + +/* + * The big monstor ioctl + */ + +static struct drm_pending_vblank_event *create_vblank_event( + struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) +{ + struct drm_pending_vblank_event *e = NULL; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + if (file_priv->event_space < sizeof e->event) { + spin_unlock_irqrestore(&dev->event_lock, flags); + goto out; + } + file_priv->event_space -= sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + + e = kzalloc(sizeof *e, GFP_KERNEL); + if (e == NULL) { + spin_lock_irqsave(&dev->event_lock, flags); + file_priv->event_space += sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + goto out; + } + + e->event.base.type = DRM_EVENT_FLIP_COMPLETE; + e->event.base.length = sizeof e->event; + e->event.user_data = user_data; + e->base.event = &e->event.base; + e->base.file_priv = file_priv; + e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; + +out: + return e; +} + +static void destroy_vblank_event(struct drm_device *dev, + struct drm_file *file_priv, struct drm_pending_vblank_event *e) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + file_priv->event_space += sizeof e->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + kfree(e); +} + +static int atomic_set_prop(struct drm_atomic_state *state, + struct drm_mode_object *obj, struct drm_property *prop, + uint64_t prop_value) +{ + struct drm_mode_object *ref; + int ret; + + if (!drm_property_change_valid_get(prop, prop_value, &ref)) + return -EINVAL; + + switch (obj->type) { + case DRM_MODE_OBJECT_CONNECTOR: { + struct drm_connector *connector = obj_to_connector(obj); + struct drm_connector_state *connector_state; + + connector_state = drm_atomic_get_connector_state(state, connector); + if (IS_ERR(connector_state)) { + ret = PTR_ERR(connector_state); + break; + } + + ret = drm_atomic_connector_set_property(connector, + connector_state, prop, prop_value); + break; + } + case DRM_MODE_OBJECT_CRTC: { + struct drm_crtc *crtc = obj_to_crtc(obj); + struct drm_crtc_state *crtc_state; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + break; + } + + ret = drm_atomic_crtc_set_property(crtc, + crtc_state, prop, prop_value); + break; + } + case DRM_MODE_OBJECT_PLANE: { + struct drm_plane *plane = obj_to_plane(obj); + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + break; + } + + ret = drm_atomic_plane_set_property(plane, + plane_state, prop, prop_value); + break; + } + default: + ret = -EINVAL; + break; + } + + drm_property_change_valid_put(prop, ref); + return ret; +} + +int drm_mode_atomic_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_atomic *arg = data; + uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr); + uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr); + uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr); + uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr); + unsigned int copied_objs, copied_props; + struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; + struct drm_plane *plane; + unsigned plane_mask = 0; + int ret = 0; + unsigned int i, j; + + /* disallow for drivers not supporting atomic: */ + if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) + return -EINVAL; + + /* disallow for userspace that has not enabled atomic cap (even + * though this may be a bit overkill, since legacy userspace + * wouldn't know how to call this ioctl) + */ + if (!file_priv->atomic) + return -EINVAL; + + if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) + return -EINVAL; + + if (arg->reserved) + return -EINVAL; + + if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) && + !dev->mode_config.async_page_flip) + return -EINVAL; + + /* can't test and expect an event at the same time. */ + if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) && + (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) + return -EINVAL; + + drm_modeset_acquire_init(&ctx, 0); + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = &ctx; + state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); + +retry: + copied_objs = 0; + copied_props = 0; + + for (i = 0; i < arg->count_objs; i++) { + uint32_t obj_id, count_props; + struct drm_mode_object *obj; + + if (get_user(obj_id, objs_ptr + copied_objs)) { + ret = -EFAULT; + goto fail; + } + + obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY); + if (!obj || !obj->properties) { + ret = -ENOENT; + goto fail; + } + + if (obj->type == DRM_MODE_OBJECT_PLANE) { + plane = obj_to_plane(obj); + plane_mask |= (1 << drm_plane_index(plane)); + plane->old_fb = plane->fb; + } + + if (get_user(count_props, count_props_ptr + copied_objs)) { + ret = -EFAULT; + goto fail; + } + + copied_objs++; + + for (j = 0; j < count_props; j++) { + uint32_t prop_id; + uint64_t prop_value; + struct drm_property *prop; + + if (get_user(prop_id, props_ptr + copied_props)) { + ret = -EFAULT; + goto fail; + } + + prop = drm_property_find(dev, prop_id); + if (!prop) { + ret = -ENOENT; + goto fail; + } + + if (get_user(prop_value, prop_values_ptr + copied_props)) { + ret = -EFAULT; + goto fail; + } + + ret = atomic_set_prop(state, obj, prop, prop_value); + if (ret) + goto fail; + + copied_props++; + } + } + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + int ncrtcs = dev->mode_config.num_crtc; + + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc_state *crtc_state = state->crtc_states[i]; + struct drm_pending_vblank_event *e; + + if (!crtc_state) + continue; + + e = create_vblank_event(dev, file_priv, arg->user_data); + if (!e) { + ret = -ENOMEM; + goto fail; + } + + crtc_state->event = e; + } + } + + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { + ret = drm_atomic_check_only(state); + /* _check_only() does not free state, unlike _commit() */ + drm_atomic_state_free(state); + } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { + ret = drm_atomic_async_commit(state); + } else { + ret = drm_atomic_commit(state); + } + + /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping + * locks (ie. while it is still safe to deref plane->state). We + * need to do this here because the driver entry points cannot + * distinguish between legacy and atomic ioctls. + */ + drm_for_each_plane_mask(plane, dev, plane_mask) { + if (ret == 0) { + struct drm_framebuffer *new_fb = plane->state->fb; + if (new_fb) + drm_framebuffer_reference(new_fb); + plane->fb = new_fb; + plane->crtc = plane->state->crtc; + } else { + plane->old_fb = NULL; + } + if (plane->old_fb) { + drm_framebuffer_unreference(plane->old_fb); + plane->old_fb = NULL; + } + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; + +fail: + if (ret == -EDEADLK) + goto backoff; + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + int ncrtcs = dev->mode_config.num_crtc; + + for (i = 0; i < ncrtcs; i++) { + struct drm_crtc_state *crtc_state = state->crtc_states[i]; + + if (!crtc_state) + continue; + + destroy_vblank_event(dev, file_priv, crtc_state->event); + crtc_state->event = NULL; + } + } + + drm_atomic_state_free(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; + +backoff: + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + + goto retry; +} diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3cb1fa09ac9e..20596423d52d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4303,7 +4303,7 @@ EXPORT_SYMBOL(drm_mode_connector_update_edid_property); * object to which the property is attached has a chance to take it's own * reference). */ -static bool drm_property_change_valid_get(struct drm_property *property, +bool drm_property_change_valid_get(struct drm_property *property, uint64_t value, struct drm_mode_object **ref) { int i; @@ -4365,7 +4365,7 @@ static bool drm_property_change_valid_get(struct drm_property *property, return false; } -static void drm_property_change_valid_put(struct drm_property *property, +void drm_property_change_valid_put(struct drm_property *property, struct drm_mode_object *ref) { if (!ref) diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index adc822312f6c..a28c0abd1a38 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -630,6 +630,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index fc4767fa723b..1dcfb685d15f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -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 @@ -914,7 +914,7 @@ struct drm_bridge { */ 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; @@ -1346,6 +1346,10 @@ extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); 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); @@ -1437,6 +1441,8 @@ extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data, 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); diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index f7b2baf7ecb2..01b2d6d0e355 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -784,6 +784,7 @@ struct drm_prime_handle { #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) #define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2) +#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic) /** * Device specific ioctls should only be in their respective headers diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index b8f9c0f2e7fe..ca788e01dab2 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -526,4 +526,27 @@ struct drm_mode_destroy_dumb { uint32_t handle; }; +/* page-flip flags are valid, plus: */ +#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 +#define DRM_MODE_ATOMIC_NONBLOCK 0x0200 +#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 + +#define DRM_MODE_ATOMIC_FLAGS (\ + DRM_MODE_PAGE_FLIP_EVENT |\ + DRM_MODE_PAGE_FLIP_ASYNC |\ + DRM_MODE_ATOMIC_TEST_ONLY |\ + DRM_MODE_ATOMIC_NONBLOCK |\ + DRM_MODE_ATOMIC_ALLOW_MODESET) + +struct drm_mode_atomic { + __u32 flags; + __u32 count_objs; + __u64 objs_ptr; + __u64 count_props_ptr; + __u64 props_ptr; + __u64 prop_values_ptr; + __u64 reserved; + __u64 user_data; +}; + #endif -- cgit v1.2.3 From 426959c945538bace94ccc590d8630c02ecd6b0f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 13 Jan 2015 07:38:53 +1000 Subject: drm: fix mismerge in drm_crtc.c Daniel merged two things in 72a3697097b8dc92f5b8362598f5730a9986eb83, but he merged this code twice, Dan's static checker spotted it. Reported-by: Dan Carpenter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7c1786df6213..caec5c3634bb 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4369,12 +4369,6 @@ bool drm_property_change_valid_get(struct drm_property *property, } 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++) -- cgit v1.2.3 From b5571e9df66c1bfb81a4a7947726c3d627d3cb41 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 22 Jul 2014 12:09:10 +0200 Subject: drm: add bus_formats and num_bus_formats fields to drm_display_info Add bus_formats and num_bus_formats fields and drm_display_info_set_bus_formats helper function to specify the bus formats supported by a given display. This information can be used by display controller drivers to configure the output interface appropriately (i.e. RGB565, RGB666 or RGB888 on raw RGB or LVDS busses). Signed-off-by: Boris Brezillon Acked-by: Laurent Pinchart Acked-by: Philipp Zabel Acked-by: Thierry Reding --- drivers/gpu/drm/drm_crtc.c | 35 +++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 8 ++++++++ 2 files changed, 43 insertions(+) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index caec5c3634bb..df90048de92e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -761,6 +761,40 @@ static void drm_mode_remove(struct drm_connector *connector, drm_mode_destroy(connector->dev, mode); } +/** + * drm_display_info_set_bus_formats - set the supported bus formats + * @info: display info to store bus formats in + * @fmts: array containing the supported bus formats + * @nfmts: the number of entries in the fmts array + * + * Store the supported bus formats in display info structure. + * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for + * a full list of available formats. + */ +int drm_display_info_set_bus_formats(struct drm_display_info *info, + const u32 *formats, + unsigned int num_formats) +{ + u32 *fmts = NULL; + + if (!formats && num_formats) + return -EINVAL; + + if (formats && num_formats) { + fmts = kmemdup(formats, sizeof(*formats) * num_formats, + GFP_KERNEL); + if (!formats) + return -ENOMEM; + } + + kfree(info->bus_formats); + info->bus_formats = fmts; + info->num_bus_formats = num_formats; + + return 0; +} +EXPORT_SYMBOL(drm_display_info_set_bus_formats); + /** * drm_connector_get_cmdline_mode - reads the user's cmdline mode * @connector: connector to quwery @@ -923,6 +957,7 @@ void drm_connector_cleanup(struct drm_connector *connector) ida_remove(&drm_connector_enum_list[connector->connector_type].ida, connector->connector_type_id); + kfree(connector->display_info.bus_formats); drm_mode_object_put(dev, &connector->base); kfree(connector->name); connector->name = NULL; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f444263055c5..0ecfb7c80601 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -139,6 +140,9 @@ struct drm_display_info { enum subpixel_order subpixel_order; u32 color_formats; + const u32 *bus_formats; + unsigned int num_bus_formats; + /* Mask of supported hdmi deep color modes */ u8 edid_hdmi_dc_modes; @@ -1282,6 +1286,10 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector); extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid); +extern int drm_display_info_set_bus_formats(struct drm_display_info *info, + const u32 *formats, + unsigned int num_formats); + static inline bool drm_property_type_is(struct drm_property *property, uint32_t type) { -- cgit v1.2.3 From e37bfa1aac6dd98ad17d98b4691c40ff561ba410 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 23 Jan 2015 21:09:30 +0100 Subject: drm: fix drm_display_info_set_bus_formats kernel doc header formats and num_formats arguments were previously called fmts and nfmts. Fix the kernel doc comment so that it matches the new argument names. Signed-off-by: Boris Brezillon Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index df90048de92e..ad2934ba0bd2 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -764,8 +764,8 @@ static void drm_mode_remove(struct drm_connector *connector, /** * drm_display_info_set_bus_formats - set the supported bus formats * @info: display info to store bus formats in - * @fmts: array containing the supported bus formats - * @nfmts: the number of entries in the fmts array + * @formats: array containing the supported bus formats + * @num_formats: the number of entries in the fmts array * * Store the supported bus formats in display info structure. * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for -- cgit v1.2.3 From 960cd9d4fef6dd9e235c0e5c0d4ed027f8a48025 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 21 Jan 2015 08:47:38 +0100 Subject: drm: Add standardized boolean props Not a new type exposed to userspace, just a standard way to create them since between range, bitmask and enum there's 3 different ways to pull out a boolean prop. Also add the kerneldoc for the recently added new prop types, which Rob forgot all about. v2: Fixup kerneldoc, spotted by Rob. Cc: Rob Clark Reviewed-by: Rob Clark Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 66 +++++++++++++++++++++++++++++++++++++++++++--- include/drm/drm_crtc.h | 2 ++ 2 files changed, 65 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index df90048de92e..c0bbb00beba7 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3810,7 +3810,7 @@ static struct drm_property *property_create_range(struct drm_device *dev, } /** - * drm_property_create_range - create a new ranged property type + * drm_property_create_range - create a new unsigned ranged property type * @dev: drm device * @flags: flags specifying the property type * @name: name of the property @@ -3821,8 +3821,8 @@ 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 integer value in the (min, max) range - * inclusive. + * Userspace is allowed to set any unsigned integer value in the (min, max) + * range inclusive. * * Returns: * A pointer to the newly created property on success, NULL on failure. @@ -3836,6 +3836,24 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags } EXPORT_SYMBOL(drm_property_create_range); +/** + * drm_property_create_signed_range - create a new signed ranged property type + * @dev: drm device + * @flags: flags specifying the property type + * @name: name of the property + * @min: minimum value of the property + * @max: maximum value of the property + * + * This creates a new generic drm property which can then be attached to a drm + * object with drm_object_attach_property. The returned property object must be + * freed with drm_property_destroy. + * + * Userspace is allowed to set any signed integer value in the (min, max) + * range inclusive. + * + * Returns: + * A pointer to the newly created property on success, NULL on failure. + */ struct drm_property *drm_property_create_signed_range(struct drm_device *dev, int flags, const char *name, int64_t min, int64_t max) @@ -3845,6 +3863,23 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev, } EXPORT_SYMBOL(drm_property_create_signed_range); +/** + * drm_property_create_object - create a new object property type + * @dev: drm device + * @flags: flags specifying the property type + * @name: name of the property + * @type: object type from DRM_MODE_OBJECT_* defines + * + * This creates a new generic drm property which can then be attached to a drm + * object with drm_object_attach_property. The returned property object must be + * freed with drm_property_destroy. + * + * Userspace is only allowed to set this to any property value of the given + * @type. Only useful for atomic properties, which is enforced. + * + * Returns: + * A pointer to the newly created property on success, NULL on failure. + */ struct drm_property *drm_property_create_object(struct drm_device *dev, int flags, const char *name, uint32_t type) { @@ -3852,6 +3887,9 @@ struct drm_property *drm_property_create_object(struct drm_device *dev, flags |= DRM_MODE_PROP_OBJECT; + if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC))) + return NULL; + property = drm_property_create(dev, flags, name, 1); if (!property) return NULL; @@ -3862,6 +3900,28 @@ struct drm_property *drm_property_create_object(struct drm_device *dev, } EXPORT_SYMBOL(drm_property_create_object); +/** + * drm_property_create_bool - create a new boolean property type + * @dev: drm device + * @flags: flags specifying the property type + * @name: name of the property + * + * This creates a new generic drm property which can then be attached to a drm + * object with drm_object_attach_property. The returned property object must be + * freed with drm_property_destroy. + * + * This is implemented as a ranged property with only {0, 1} as valid values. + * + * Returns: + * A pointer to the newly created property on success, NULL on failure. + */ +struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, + const char *name) +{ + return drm_property_create_range(dev, flags, name, 0, 1); +} +EXPORT_SYMBOL(drm_property_create_bool); + /** * drm_property_add_enum - add a possible value to an enumeration property * @property: enumeration property to change diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 0ecfb7c80601..c4e36f60b3ef 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1345,6 +1345,8 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev, int64_t min, int64_t max); struct drm_property *drm_property_create_object(struct drm_device *dev, int flags, const char *name, uint32_t type); +struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags, + const char *name); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -- cgit v1.2.3 From eab3bbeffd152125ae0f90863b8e9bc8eef49423 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 22 Jan 2015 16:36:21 +0100 Subject: drm/atomic: Add drm_crtc_state->active This is the infrastructure for DPMS ported to the atomic world. Fundamental changes compare to legacy DPMS are: - No more per-connector dpms state, instead there's just one per each display pipeline. So if you clone either you have to unclone first if you only want to switch off one screen, or you just switch of everything (like all desktops do). This massively reduces complexity for cloning since now there's no more half-enabled cloned configs to consider. - Only on/off, dpms standby/suspend are as dead as real CRTs. Again reduces complexity a lot. Now especially for backwards compat the really important part for dpms support is that dpms on always succeeds (except for hw death and unplugged cables ofc). Which means everything that could fail (like configuration checking, resources assignments and buffer management) must be done irrespective from ->active. ->active is really only a toggle to change the hardware state. More precisely: - Drivers MUST NOT look at ->active in their ->atomic_check callbacks. Changes to ->active MUST always suceed if nothing else changes. - Drivers using the atomic helpers MUST NOT look at ->active anywhere, period. The helpers will take care of calling the respective enable/modeset/disable hooks as necessary. As before the helpers will carefully keep track of the state and not call any hooks unecessarily, so still no double-disables or enables like with crtc helpers. - ->mode_set hooks are only called when the mode or output configuration changes, not for changes in ->active state. - Drivers which reconstruct the state objects in their ->reset hooks or through some other hw state readout infrastructure must ensure that ->active reflects actual hw state. This just implements the core bits and helper logic, a subsequent patch will implement the helper code to implement legacy dpms with this. v2: Rebase on top of the drm ioctl work: - Move crtc checks to the core check function. - Also check for ->active_changed when deciding whether a modeset might happen (for the ALLOW_MODESET mode). - Expose the ->active state with an atomic prop. v3: Review from Rob - Spelling fix in comment. - Extract needs_modeset helper to consolidate the ->mode_changed || ->active_changed checks. v4: Fixup fumble between crtc->state and crtc_state. Cc: Rob Clark Reviewed-by: Thierry Reding Tested-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 18 +++++++++++-- drivers/gpu/drm/drm_atomic_helper.c | 54 +++++++++++++++++++++++++++++++++---- drivers/gpu/drm/drm_crtc.c | 10 +++++++ include/drm/drm_crtc.h | 3 +++ 4 files changed, 78 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1e38dfc8e462..ee68267bb326 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -241,7 +241,13 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { - if (crtc->funcs->atomic_set_property) + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + + /* FIXME: Mode prop is missing, which also controls ->enable. */ + if (property == config->prop_active) { + state->active = val; + } else if (crtc->funcs->atomic_set_property) return crtc->funcs->atomic_set_property(crtc, state, property, val); return -EINVAL; } @@ -282,6 +288,13 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc, * * TODO: Add generic modeset state checks once we support those. */ + + if (state->active && !state->enable) { + DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n", + crtc->base.id); + return -EINVAL; + } + return 0; } @@ -976,7 +989,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (!crtc) continue; - if (crtc_state->mode_changed) { + if (crtc_state->mode_changed || + crtc_state->active_changed) { DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n", crtc->base.id); return -EINVAL; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 541ba833ed36..3f17933b1d2c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -330,6 +330,12 @@ mode_fixup(struct drm_atomic_state *state) return 0; } +static bool +needs_modeset(struct drm_crtc_state *state) +{ + return state->mode_changed || state->active_changed; +} + /** * drm_atomic_helper_check - validate state object for modeset changes * @dev: DRM device @@ -404,12 +410,27 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, crtc = state->crtcs[i]; crtc_state = state->crtc_states[i]; - if (!crtc || !crtc_state->mode_changed) + if (!crtc) continue; - DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n", + /* + * We must set ->active_changed after walking connectors for + * otherwise an update that only changes active would result in + * a full modeset because update_connector_routing force that. + */ + if (crtc->state->active != crtc_state->active) { + DRM_DEBUG_KMS("[CRTC:%d] active changed\n", + crtc->base.id); + crtc_state->active_changed = true; + } + + if (!needs_modeset(crtc_state)) + continue; + + DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n", crtc->base.id, - crtc_state->enable ? 'y' : 'n'); + crtc_state->enable ? 'y' : 'n', + crtc_state->active ? 'y' : 'n'); ret = drm_atomic_add_affected_connectors(state, crtc); if (ret != 0) @@ -545,6 +566,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) struct drm_connector *connector; struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; + struct drm_crtc_state *old_crtc_state; old_conn_state = old_state->connector_states[i]; connector = old_state->connectors[i]; @@ -554,6 +576,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) if (!old_conn_state || !old_conn_state->crtc) continue; + old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)]; + + if (!old_crtc_state->active) + continue; + encoder = old_conn_state->best_encoder; /* We shouldn't get this far if we didn't previously have @@ -586,11 +613,16 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) for (i = 0; i < ncrtcs; i++) { struct drm_crtc_helper_funcs *funcs; struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; crtc = old_state->crtcs[i]; + old_crtc_state = old_state->crtc_states[i]; /* Shut down everything that needs a full modeset. */ - if (!crtc || !crtc->state->mode_changed) + if (!crtc || !needs_modeset(crtc->state)) + continue; + + if (!old_crtc_state->active) continue; funcs = crtc->helper_private; @@ -697,6 +729,9 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) mode = &new_crtc_state->mode; adjusted_mode = &new_crtc_state->adjusted_mode; + if (!new_crtc_state->mode_changed) + continue; + /* * Each encoder has at most one connector (since we always steal * it away), so we won't call call mode_set hooks twice. @@ -749,7 +784,10 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, crtc = old_state->crtcs[i]; /* Need to filter out CRTCs where only planes change. */ - if (!crtc || !crtc->state->mode_changed) + if (!crtc || !needs_modeset(crtc->state)) + continue; + + if (!crtc->state->active) continue; funcs = crtc->helper_private; @@ -768,6 +806,9 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev, if (!connector || !connector->state->best_encoder) continue; + if (!connector->state->crtc->state->active) + continue; + encoder = connector->state->best_encoder; funcs = encoder->helper_private; @@ -1518,6 +1559,7 @@ retry: WARN_ON(set->num_connectors); crtc_state->enable = false; + crtc_state->active = false; ret = drm_atomic_set_crtc_for_plane(primary_state, NULL); if (ret != 0) @@ -1532,6 +1574,7 @@ retry: WARN_ON(!set->num_connectors); crtc_state->enable = true; + crtc_state->active = true; drm_mode_copy(&crtc_state->mode, set->mode); ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); @@ -1894,6 +1937,7 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc) if (state) { state->mode_changed = false; + state->active_changed = false; state->planes_changed = false; state->event = NULL; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index c0bbb00beba7..419f9d915c78 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -691,6 +691,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, if (cursor) cursor->possible_crtcs = 1 << drm_crtc_index(crtc); + if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { + drm_object_attach_property(&crtc->base, config->prop_active, 0); + } + return 0; } EXPORT_SYMBOL(drm_crtc_init_with_planes); @@ -1481,6 +1485,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_crtc_id = prop; + prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, + "ACTIVE"); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_active = prop; + return 0; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c4e36f60b3ef..0a738e1d4f37 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -253,6 +253,7 @@ struct drm_atomic_state; * @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 + * @active_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 * update to ensure framebuffer cleanup isn't done too early @@ -278,6 +279,7 @@ struct drm_crtc_state { /* computed state bits used by helpers and drivers */ bool planes_changed : 1; bool mode_changed : 1; + bool active_changed : 1; /* attached planes bitmask: * WARNING: transitional helpers do not maintain plane_mask so @@ -1113,6 +1115,7 @@ struct drm_mode_config { struct drm_property *prop_crtc_h; struct drm_property *prop_fb_id; struct drm_property *prop_crtc_id; + struct drm_property *prop_active; /* DVI-I properties */ struct drm_property *dvi_i_subconnector_property; -- cgit v1.2.3 From b07b90fd178a4797b0454ead491b717b41046bee Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Tue, 20 Jan 2015 22:08:43 +0530 Subject: drm/bridge: do not pass drm_bridge_funcs to drm_bridge_init Assign the pointer to bridge ops structure(drm_bridge_funcs) in the bridge driver itself, instead of passing it to drm_bridge_init. This will allow bridge driver developer to pack bridge private information inside the bridge object and pass only the drm-relevant information to drm_bridge_init. Signed-off-by: Ajay Kumar Acked-by: Inki Dae Tested-by: Rahul Sharma Tested-by: Javier Martinez Canillas Tested-by: Gustavo Padovan Tested-by: Sjoerd Simons Signed-off-by: Thierry Reding --- drivers/gpu/drm/bridge/ptn3460.c | 3 ++- drivers/gpu/drm/drm_crtc.c | 5 +---- drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 3 ++- drivers/gpu/drm/sti/sti_hda.c | 3 ++- drivers/gpu/drm/sti/sti_hdmi.c | 3 ++- include/drm/drm_crtc.h | 3 +-- 6 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index 4db38e1f7a1f..a2ddc8d73c6a 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -313,7 +313,8 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, goto err; } - ret = drm_bridge_init(dev, &ptn_bridge->bridge, &ptn3460_bridge_funcs); + ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; + ret = drm_bridge_init(dev, &ptn_bridge->bridge); if (ret) { DRM_ERROR("Failed to initialize bridge with drm\n"); goto err; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b459888f6310..7936c5c2314c 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1069,7 +1069,6 @@ EXPORT_SYMBOL(drm_connector_unplug_all); * drm_bridge_init - initialize a drm transcoder/bridge * @dev: drm device * @bridge: transcoder/bridge to set up - * @funcs: bridge function table * * Initialises a preallocated bridge. Bridges should be * subclassed as part of driver connector objects. @@ -1077,8 +1076,7 @@ EXPORT_SYMBOL(drm_connector_unplug_all); * Returns: * Zero on success, error code on failure. */ -int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, - const struct drm_bridge_funcs *funcs) +int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge) { int ret; @@ -1089,7 +1087,6 @@ int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, goto out; bridge->dev = dev; - bridge->funcs = funcs; list_add_tail(&bridge->head, &dev->mode_config.bridge_list); dev->mode_config.num_bridge++; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 6902ad6da710..52ed2b53b246 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -220,8 +220,9 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi) hdmi_bridge->hdmi = hdmi; bridge = &hdmi_bridge->base; + bridge->funcs = &hdmi_bridge_funcs; - drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs); + drm_bridge_init(hdmi->dev, bridge); return bridge; diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 2ae9a9b73666..6cf145de9b41 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -664,7 +664,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) return -ENOMEM; bridge->driver_private = hda; - drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs); + bridge->funcs = &sti_hda_bridge_funcs; + drm_bridge_init(drm_dev, bridge); encoder->bridge = bridge; connector->encoder = encoder; diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index d032e024b0b8..74e943e655d1 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -635,7 +635,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) goto err_adapt; bridge->driver_private = hdmi; - drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs); + bridge->funcs = &sti_hdmi_bridge_funcs; + drm_bridge_init(drm_dev, bridge); encoder->bridge = bridge; connector->encoder = encoder; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 02614170c034..15bb762fb316 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1222,8 +1222,7 @@ extern unsigned int drm_connector_index(struct drm_connector *connector); /* helper to unplug all connectors from sysfs for device */ extern void drm_connector_unplug_all(struct drm_device *dev); -extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, - const struct drm_bridge_funcs *funcs); +extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge); extern void drm_bridge_cleanup(struct drm_bridge *bridge); extern int drm_encoder_init(struct drm_device *dev, -- cgit v1.2.3 From 3d3f8b1f8b62c3a010976269df454baa9246fc65 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Tue, 20 Jan 2015 22:08:44 +0530 Subject: drm/bridge: make bridge registration independent of drm flow Currently, third party bridge drivers(ptn3460) are dependent on the corresponding encoder driver init, since bridge driver needs a drm_device pointer to finish drm initializations. The encoder driver passes the drm_device pointer to the bridge driver. Because of this dependency, third party drivers like ptn3460 doesn't adhere to the driver model. In this patch, we reframe the bridge registration framework so that bridge initialization is split into 2 steps, and bridge registration happens independent of drm flow: --Step 1: gather all the bridge settings independent of drm and add the bridge onto a global list of bridges. --Step 2: when the encoder driver is probed, call drm_bridge_attach for the corresponding bridge so that the bridge receives drm_device pointer and continues with connector and other drm initializations. The old set of bridge helpers are removed, and a set of new helpers are added to accomplish the 2 step initialization. The bridge devices register themselves onto global list of bridges when they get probed by calling "drm_bridge_add". The parent encoder driver waits till the bridge is available in the lookup table(by calling "of_drm_find_bridge") and then continues with its initialization. The encoder driver should also call "drm_bridge_attach" to pass on the drm_device to the bridge object. drm_bridge_attach inturn calls "bridge->funcs->attach" so that bridge can continue with drm related initializations. Signed-off-by: Ajay Kumar Acked-by: Inki Dae Tested-by: Rahul Sharma Tested-by: Javier Martinez Canillas Tested-by: Gustavo Padovan Tested-by: Sjoerd Simons Signed-off-by: Thierry Reding --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/bridge/ptn3460.c | 27 +++++----- drivers/gpu/drm/drm_bridge.c | 91 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 67 ------------------------- drivers/gpu/drm/msm/hdmi/hdmi.c | 4 +- drivers/gpu/drm/msm/hdmi/hdmi.h | 1 + drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 6 +-- drivers/gpu/drm/sti/sti_hda.c | 10 +--- drivers/gpu/drm/sti/sti_hdmi.c | 10 +--- include/drm/bridge/ptn3460.h | 8 +++ include/drm/drm_crtc.h | 26 +++++----- 11 files changed, 133 insertions(+), 119 deletions(-) create mode 100644 drivers/gpu/drm/drm_bridge.c (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index cf0eed8208b5..2c239b99de64 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ drm_rect.o drm_vma_manager.o drm_flip_work.o \ - drm_modeset_lock.o drm_atomic.o + drm_modeset_lock.o drm_atomic.o drm_bridge.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index a2ddc8d73c6a..4a818c1b62e0 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -176,24 +176,11 @@ static void ptn3460_post_disable(struct drm_bridge *bridge) { } -static void ptn3460_bridge_destroy(struct drm_bridge *bridge) -{ - struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); - - drm_bridge_cleanup(bridge); - if (gpio_is_valid(ptn_bridge->gpio_pd_n)) - gpio_free(ptn_bridge->gpio_pd_n); - if (gpio_is_valid(ptn_bridge->gpio_rst_n)) - gpio_free(ptn_bridge->gpio_rst_n); - /* Nothing else to free, we've got devm allocated memory */ -} - static struct drm_bridge_funcs ptn3460_bridge_funcs = { .pre_enable = ptn3460_pre_enable, .enable = ptn3460_enable, .disable = ptn3460_disable, .post_disable = ptn3460_post_disable, - .destroy = ptn3460_bridge_destroy, }; static int ptn3460_get_modes(struct drm_connector *connector) @@ -314,7 +301,7 @@ int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, } ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; - ret = drm_bridge_init(dev, &ptn_bridge->bridge); + ret = drm_bridge_attach(dev, &ptn_bridge->bridge); if (ret) { DRM_ERROR("Failed to initialize bridge with drm\n"); goto err; @@ -343,3 +330,15 @@ err: return ret; } EXPORT_SYMBOL(ptn3460_init); + +void ptn3460_destroy(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_free(ptn_bridge->gpio_pd_n); + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) + gpio_free(ptn_bridge->gpio_rst_n); + /* Nothing else to free, we've got devm allocated memory */ +} +EXPORT_SYMBOL(ptn3460_destroy); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c new file mode 100644 index 000000000000..d1187e571c6d --- /dev/null +++ b/drivers/gpu/drm/drm_bridge.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +#include "drm/drmP.h" + +static DEFINE_MUTEX(bridge_lock); +static LIST_HEAD(bridge_list); + +int drm_bridge_add(struct drm_bridge *bridge) +{ + mutex_lock(&bridge_lock); + list_add_tail(&bridge->list, &bridge_list); + mutex_unlock(&bridge_lock); + + return 0; +} +EXPORT_SYMBOL(drm_bridge_add); + +void drm_bridge_remove(struct drm_bridge *bridge) +{ + mutex_lock(&bridge_lock); + list_del_init(&bridge->list); + mutex_unlock(&bridge_lock); +} +EXPORT_SYMBOL(drm_bridge_remove); + +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge) +{ + if (!dev || !bridge) + return -EINVAL; + + if (bridge->dev) + return -EBUSY; + + bridge->dev = dev; + + if (bridge->funcs->attach) + return bridge->funcs->attach(bridge); + + return 0; +} +EXPORT_SYMBOL(drm_bridge_attach); + +#ifdef CONFIG_OF +struct drm_bridge *of_drm_find_bridge(struct device_node *np) +{ + struct drm_bridge *bridge; + + mutex_lock(&bridge_lock); + + list_for_each_entry(bridge, &bridge_list, list) { + if (bridge->of_node == np) { + mutex_unlock(&bridge_lock); + return bridge; + } + } + + mutex_unlock(&bridge_lock); + return NULL; +} +EXPORT_SYMBOL(of_drm_find_bridge); +#endif + +MODULE_AUTHOR("Ajay Kumar "); +MODULE_DESCRIPTION("DRM bridge infrastructure"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7936c5c2314c..0e4ec700b0a6 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1065,58 +1065,6 @@ void drm_connector_unplug_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_connector_unplug_all); -/** - * drm_bridge_init - initialize a drm transcoder/bridge - * @dev: drm device - * @bridge: transcoder/bridge to set up - * - * Initialises a preallocated bridge. Bridges should be - * subclassed as part of driver connector objects. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge) -{ - int ret; - - drm_modeset_lock_all(dev); - - ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE); - if (ret) - goto out; - - bridge->dev = dev; - - list_add_tail(&bridge->head, &dev->mode_config.bridge_list); - dev->mode_config.num_bridge++; - - out: - drm_modeset_unlock_all(dev); - return ret; -} -EXPORT_SYMBOL(drm_bridge_init); - -/** - * drm_bridge_cleanup - cleans up an initialised bridge - * @bridge: bridge to cleanup - * - * Cleans up the bridge but doesn't free the object. - */ -void drm_bridge_cleanup(struct drm_bridge *bridge) -{ - struct drm_device *dev = bridge->dev; - - drm_modeset_lock_all(dev); - drm_mode_object_put(dev, &bridge->base); - list_del(&bridge->head); - dev->mode_config.num_bridge--; - drm_modeset_unlock_all(dev); - - memset(bridge, 0, sizeof(*bridge)); -} -EXPORT_SYMBOL(drm_bridge_cleanup); - /** * drm_encoder_init - Init a preallocated encoder * @dev: drm device @@ -1712,7 +1660,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr total_objects += dev->mode_config.num_crtc; total_objects += dev->mode_config.num_connector; total_objects += dev->mode_config.num_encoder; - total_objects += dev->mode_config.num_bridge; group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); if (!group->id_list) @@ -1721,7 +1668,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr group->num_crtcs = 0; group->num_connectors = 0; group->num_encoders = 0; - group->num_bridges = 0; return 0; } @@ -1741,7 +1687,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; - struct drm_bridge *bridge; int ret; ret = drm_mode_group_init(dev, group); @@ -1759,11 +1704,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, group->id_list[group->num_crtcs + group->num_encoders + group->num_connectors++] = connector->base.id; - list_for_each_entry(bridge, &dev->mode_config.bridge_list, head) - group->id_list[group->num_crtcs + group->num_encoders + - group->num_connectors + group->num_bridges++] = - bridge->base.id; - return 0; } EXPORT_SYMBOL(drm_mode_group_init_legacy_group); @@ -5440,7 +5380,6 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.connector_list); - INIT_LIST_HEAD(&dev->mode_config.bridge_list); INIT_LIST_HEAD(&dev->mode_config.encoder_list); INIT_LIST_HEAD(&dev->mode_config.property_list); INIT_LIST_HEAD(&dev->mode_config.property_blob_list); @@ -5480,7 +5419,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_connector *connector, *ot; struct drm_crtc *crtc, *ct; struct drm_encoder *encoder, *enct; - struct drm_bridge *bridge, *brt; struct drm_framebuffer *fb, *fbt; struct drm_property *property, *pt; struct drm_property_blob *blob, *bt; @@ -5491,11 +5429,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) encoder->funcs->destroy(encoder); } - list_for_each_entry_safe(bridge, brt, - &dev->mode_config.bridge_list, head) { - bridge->funcs->destroy(bridge); - } - list_for_each_entry_safe(connector, ot, &dev->mode_config.connector_list, head) { connector->funcs->destroy(connector); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 062c68725376..95f7b8d0f3ef 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi, return 0; fail: - /* bridge/connector are normally destroyed by drm: */ + /* bridge is normally destroyed by drm: */ if (hdmi->bridge) { - hdmi->bridge->funcs->destroy(hdmi->bridge); + hdmi_bridge_destroy(hdmi->bridge); hdmi->bridge = NULL; } if (hdmi->connector) { diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 43e654f751b7..4d4cad42a776 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate); */ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi); +void hdmi_bridge_destroy(struct drm_bridge *bridge); /* * hdmi connector: diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 52ed2b53b246..d6f8d5818e18 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -23,10 +23,9 @@ struct hdmi_bridge { }; #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) -static void hdmi_bridge_destroy(struct drm_bridge *bridge) +void hdmi_bridge_destroy(struct drm_bridge *bridge) { struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); - drm_bridge_cleanup(bridge); kfree(hdmi_bridge); } @@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = { .disable = hdmi_bridge_disable, .post_disable = hdmi_bridge_post_disable, .mode_set = hdmi_bridge_mode_set, - .destroy = hdmi_bridge_destroy, }; @@ -222,7 +220,7 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi) bridge = &hdmi_bridge->base; bridge->funcs = &hdmi_bridge_funcs; - drm_bridge_init(hdmi->dev, bridge); + drm_bridge_attach(hdmi->dev, bridge); return bridge; diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 6cf145de9b41..a9bbb081ecad 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge) /* do nothing */ } -static void sti_hda_brigde_destroy(struct drm_bridge *bridge) -{ - drm_bridge_cleanup(bridge); - kfree(bridge); -} - static const struct drm_bridge_funcs sti_hda_bridge_funcs = { .pre_enable = sti_hda_pre_enable, .enable = sti_hda_bridge_nope, .disable = sti_hda_disable, .post_disable = sti_hda_bridge_nope, .mode_set = sti_hda_set_mode, - .destroy = sti_hda_brigde_destroy, }; static int sti_hda_connector_get_modes(struct drm_connector *connector) @@ -665,7 +658,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) bridge->driver_private = hda; bridge->funcs = &sti_hda_bridge_funcs; - drm_bridge_init(drm_dev, bridge); + drm_bridge_attach(drm_dev, bridge); encoder->bridge = bridge; connector->encoder = encoder; @@ -694,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) err_sysfs: drm_connector_unregister(drm_connector); err_connector: - drm_bridge_cleanup(bridge); drm_connector_cleanup(drm_connector); return -EINVAL; } diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 74e943e655d1..e840ca5de401 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge) /* do nothing */ } -static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge) -{ - drm_bridge_cleanup(bridge); - kfree(bridge); -} - static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = { .pre_enable = sti_hdmi_pre_enable, .enable = sti_hdmi_bridge_nope, .disable = sti_hdmi_disable, .post_disable = sti_hdmi_bridge_nope, .mode_set = sti_hdmi_set_mode, - .destroy = sti_hdmi_brigde_destroy, }; static int sti_hdmi_connector_get_modes(struct drm_connector *connector) @@ -636,7 +629,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) bridge->driver_private = hdmi; bridge->funcs = &sti_hdmi_bridge_funcs; - drm_bridge_init(drm_dev, bridge); + drm_bridge_attach(drm_dev, bridge); encoder->bridge = bridge; connector->encoder = encoder; @@ -668,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) err_sysfs: drm_connector_unregister(drm_connector); err_connector: - drm_bridge_cleanup(bridge); drm_connector_cleanup(drm_connector); err_adapt: put_device(&hdmi->ddc_adapt->dev); diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h index ff62344fec6c..b11f8e17e72f 100644 --- a/include/drm/bridge/ptn3460.h +++ b/include/drm/bridge/ptn3460.h @@ -15,6 +15,7 @@ #define _DRM_BRIDGE_PTN3460_H_ struct drm_device; +struct drm_bridge; struct drm_encoder; struct i2c_client; struct device_node; @@ -23,6 +24,9 @@ struct device_node; int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, struct i2c_client *client, struct device_node *node); + +void ptn3460_destroy(struct drm_bridge *bridge); + #else static inline int ptn3460_init(struct drm_device *dev, @@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev, return 0; } +static inline void ptn3460_destroy(struct drm_bridge *bridge) +{ +} + #endif #endif diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 15bb762fb316..920e21a8f3fd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -868,15 +868,16 @@ struct drm_plane { /** * struct drm_bridge_funcs - drm_bridge control functions + * @attach: Called during drm_bridge_attach * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge * @disable: Called right before encoder prepare, disables the bridge * @post_disable: Called right after encoder prepare, for lockstepped disable * @mode_set: Set this mode to the bridge * @pre_enable: Called right before encoder commit, for lockstepped commit * @enable: Called right after encoder commit, enables the bridge - * @destroy: make object go away */ struct drm_bridge_funcs { + int (*attach)(struct drm_bridge *bridge); bool (*mode_fixup)(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); @@ -887,22 +888,24 @@ struct drm_bridge_funcs { struct drm_display_mode *adjusted_mode); void (*pre_enable)(struct drm_bridge *bridge); void (*enable)(struct drm_bridge *bridge); - void (*destroy)(struct drm_bridge *bridge); }; /** * struct drm_bridge - central DRM bridge control structure * @dev: DRM device this bridge belongs to - * @head: list management + * @of_node: device node pointer to the bridge + * @list: to keep track of all added bridges * @base: base mode object * @funcs: control functions * @driver_private: pointer to the bridge driver's internal context */ struct drm_bridge { struct drm_device *dev; - struct list_head head; - - struct drm_mode_object base; + struct drm_encoder *encoder; +#ifdef CONFIG_OF + struct device_node *of_node; +#endif + struct list_head list; const struct drm_bridge_funcs *funcs; void *driver_private; @@ -1007,7 +1010,6 @@ struct drm_mode_group { uint32_t num_crtcs; uint32_t num_encoders; uint32_t num_connectors; - uint32_t num_bridges; /* list of object IDs for this group */ uint32_t *id_list; @@ -1026,8 +1028,6 @@ struct drm_mode_group { * @fb_list: list of framebuffers available * @num_connector: number of connectors on this device * @connector_list: list of connector objects - * @num_bridge: number of bridges on this device - * @bridge_list: list of bridge objects * @num_encoder: number of encoders on this device * @encoder_list: list of encoder objects * @num_overlay_plane: number of overlay planes on this device @@ -1072,8 +1072,6 @@ struct drm_mode_config { int num_connector; struct list_head connector_list; - int num_bridge; - struct list_head bridge_list; int num_encoder; struct list_head encoder_list; @@ -1222,8 +1220,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector); /* helper to unplug all connectors from sysfs for device */ extern void drm_connector_unplug_all(struct drm_device *dev); -extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge); -extern void drm_bridge_cleanup(struct drm_bridge *bridge); +extern int drm_bridge_add(struct drm_bridge *bridge); +extern void drm_bridge_remove(struct drm_bridge *bridge); +extern struct drm_bridge *of_drm_find_bridge(struct device_node *np); +extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge); extern int drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, -- cgit v1.2.3 From 944579c5a474e5faffd3ff2ee0e45eb7c53c3fd3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 28 Jan 2015 09:43:35 +0300 Subject: drm: Check the right variable when setting formats When setting the video bus supported formats for a display device using drm_display_info_set_bus_formats(), check for the proper variable after duplicating memory. Signed-off-by: Dan Carpenter Reviewed-by: Daniel Kurtz Signed-off-by: Thierry Reding --- drivers/gpu/drm/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0e4ec700b0a6..6b00173d1be4 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -787,7 +787,7 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, if (formats && num_formats) { fmts = kmemdup(formats, sizeof(*formats) * num_formats, GFP_KERNEL); - if (!formats) + if (!fmts) return -ENOMEM; } -- cgit v1.2.3 From 2caa80e72b57c6216aec6f6a11fcfb4fec46daa0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 22 Feb 2015 11:38:36 +0100 Subject: drm: Fix deadlock due to getconnector locking changes In commit ccfc08655d5fd5076828f45fb09194c070f2f63a Author: Rob Clark Date: Thu Dec 18 16:01:48 2014 -0500 drm: tweak getconnector locking We need to extend the locking to cover connector->state reading for atomic drivers, but the above commit was a bit too eager and also included the fill_modes callback. Which on i915 on old platforms using load detection needs to acquire modeset locks, resulting in a deadlock on output probing. Reported-by: Marc Finet Cc: Marc Finet Cc: robdclark@gmail.com Signed-off-by: Daniel Vetter Reviewed-by: Rob Clark Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6b00173d1be4..6b6b07ff720b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -2127,7 +2127,6 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, 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) { @@ -2157,6 +2156,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, 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; -- cgit v1.2.3 From 9a6f5130143c17b91e0a3cbf5cc2d8c1e5a80a63 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Feb 2015 13:45:26 +0000 Subject: drm: Don't assign fbs for universal cursor support to files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The internal framebuffers we create to remap legacy cursor ioctls to plane operations for the universal plane support shouldn't be linke to the file like normal userspace framebuffers. This bug goes back to the original universal cursor plane support introduced in commit 161d0dc1dccb17ff7a38f462c7c0d4ef8bcc5662 Author: Matt Roper Date: Tue Jun 10 08:28:10 2014 -0700 drm: Support legacy cursor ioctls via universal planes when possible (v4) The isn't too disastrous since fbs are small, we only create one when the cursor bo gets changed and ultimately they'll be reaped when the window server restarts. Conceptually we'd want to just pass NULL for file_priv when creating it, but the driver needs the file to lookup the underlying buffer object for cursor id. Instead let's move the file_priv linking out of add_framebuffer_internal() into the addfb ioctl implementation, which is the only place it is needed. And also rename the function for a more accurate since it only creates the fb, but doesn't add it anywhere. Signed-off-by: Daniel Vetter (fix & commit msg) Signed-off-by: Chris Wilson (provider of lipstick) Reviewed-by: Matt Roper Cc: Ville Syrjälä Cc: Matt Roper Cc: Rob Clark Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/gpu/drm/drm_crtc.c') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 6b6b07ff720b..f6d04c7b5115 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -43,9 +43,10 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, - struct drm_mode_fb_cmd2 *r, - struct drm_file *file_priv); +static struct drm_framebuffer * +internal_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd2 *r, + struct drm_file *file_priv); /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ @@ -2908,13 +2909,11 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, */ if (req->flags & DRM_MODE_CURSOR_BO) { if (req->handle) { - fb = add_framebuffer_internal(dev, &fbreq, file_priv); + fb = internal_framebuffer_create(dev, &fbreq, file_priv); if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to wrap cursor buffer in drm framebuffer\n"); return PTR_ERR(fb); } - - drm_framebuffer_reference(fb); } else { fb = NULL; } @@ -3267,9 +3266,10 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) return 0; } -static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, - struct drm_mode_fb_cmd2 *r, - struct drm_file *file_priv) +static struct drm_framebuffer * +internal_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd2 *r, + struct drm_file *file_priv) { struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; @@ -3301,12 +3301,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, return fb; } - mutex_lock(&file_priv->fbs_lock); - r->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 fb; } @@ -3328,15 +3322,24 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, int drm_mode_addfb2(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_mode_fb_cmd2 *r = data; struct drm_framebuffer *fb; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - fb = add_framebuffer_internal(dev, data, file_priv); + fb = internal_framebuffer_create(dev, r, file_priv); if (IS_ERR(fb)) return PTR_ERR(fb); + /* Transfer ownership to the filp for reaping on close */ + + DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); + mutex_lock(&file_priv->fbs_lock); + r->fb_id = fb->base.id; + list_add(&fb->filp_head, &file_priv->fbs); + mutex_unlock(&file_priv->fbs_lock); + return 0; } -- cgit v1.2.3