drm: Make the connector dpms callback return a value, v2.
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Tue, 21 Jul 2015 09:34:55 +0000 (11:34 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 27 Jul 2015 14:23:28 +0000 (16:23 +0200)
This is required to properly handle failing dpms calls.
When making a wait in i915 interruptible, I've noticed
that the dpms sequence could fail with -ERESTARTSYS because
it was waiting interruptibly for flips. So from now on
allow drivers to fail in their connector dpms callback.

Encoder and crtc dpms callbacks are unaffected.

Changes since v1:
- Update kerneldoc for the drm helper functions.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
[danvet: Resolve conflicts due to different merge order.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
19 files changed:
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/radeon/radeon_dp_mst.c
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/rgb.c
drivers/gpu/drm/tegra/sor.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
include/drm/drm_atomic_helper.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h

index 5ec13c7cc832a2eff9f3defb82d56a4b231a64d6..57847ae8ce8ce1f704b2aac9da0e25f7729d5873 100644 (file)
@@ -1974,9 +1974,12 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip);
  * implementing the legacy DPMS connector interface. It computes the new desired
  * ->active state for the corresponding CRTC (if the connector is enabled) and
  *  updates it.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
  */
-void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
-                                     int mode)
+int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+                                    int mode)
 {
        struct drm_mode_config *config = &connector->dev->mode_config;
        struct drm_atomic_state *state;
@@ -1985,6 +1988,7 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
        struct drm_connector *tmp_connector;
        int ret;
        bool active = false;
+       int old_mode = connector->dpms;
 
        if (mode != DRM_MODE_DPMS_ON)
                mode = DRM_MODE_DPMS_OFF;
@@ -1993,18 +1997,19 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
        crtc = connector->state->crtc;
 
        if (!crtc)
-               return;
+               return 0;
 
-       /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */
        state = drm_atomic_state_alloc(connector->dev);
        if (!state)
-               return;
+               return -ENOMEM;
 
        state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
 retry:
        crtc_state = drm_atomic_get_crtc_state(state, crtc);
-       if (IS_ERR(crtc_state))
-               return;
+       if (IS_ERR(crtc_state)) {
+               ret = PTR_ERR(crtc_state);
+               goto fail;
+       }
 
        WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
 
@@ -2023,17 +2028,16 @@ retry:
        if (ret != 0)
                goto fail;
 
-       /* Driver takes ownership of state on successful async commit. */
-       return;
+       /* Driver takes ownership of state on successful commit. */
+       return 0;
 fail:
        if (ret == -EDEADLK)
                goto backoff;
 
+       connector->dpms = old_mode;
        drm_atomic_state_free(state);
 
-       WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret);
-
-       return;
+       return ret;
 backoff:
        drm_atomic_state_clear(state);
        drm_atomic_legacy_backoff(state);
index 1f0da41ae2a150278ab2bc9de7fcf581285e3f08..dfac394d060207d66121400211f580ff86d7e5cf 100644 (file)
@@ -4753,9 +4753,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
 
        /* Do DPMS ourselves */
        if (property == connector->dev->mode_config.dpms_property) {
-               if (connector->funcs->dpms)
-                       (*connector->funcs->dpms)(connector, (int)value);
                ret = 0;
+               if (connector->funcs->dpms)
+                       ret = (*connector->funcs->dpms)(connector, (int)value);
        } else if (connector->funcs->set_property)
                ret = connector->funcs->set_property(connector, property, value);
 
index d3d038f05bf7f7ed2bd2d19e3a2db94ff33fe45f..ef534758a02c6f946061107aaa0262527c8a25fb 100644 (file)
@@ -762,15 +762,18 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)
  * implementing the DPMS connector attribute. It computes the new desired DPMS
  * state for all encoders and crtcs in the output mesh and calls the ->dpms()
  * callback provided by the driver appropriately.
+ *
+ * Returns:
+ * Always returns 0.
  */
-void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
+int drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_encoder *encoder = connector->encoder;
        struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
        int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF;
 
        if (mode == connector->dpms)
-               return;
+               return 0;
 
        old_dpms = connector->dpms;
        connector->dpms = mode;
@@ -802,7 +805,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
                }
        }
 
-       return;
+       return 0;
 }
 EXPORT_SYMBOL(drm_helper_connector_dpms);
 
index 521af2c069cb6aed90e379501d3fbc39c24df6e9..5d78c1feec8140f12d0c1676c74386b561111991 100644 (file)
@@ -237,7 +237,7 @@ static void intel_enable_crt(struct intel_encoder *encoder)
 }
 
 /* Special dpms function to support cloning between dvo/sdvo/crt. */
-static void intel_crt_dpms(struct drm_connector *connector, int mode)
+static int intel_crt_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_device *dev = connector->dev;
        struct intel_encoder *encoder = intel_attached_encoder(connector);
@@ -249,7 +249,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode)
                mode = DRM_MODE_DPMS_OFF;
 
        if (mode == connector->dpms)
-               return;
+               return 0;
 
        old_dpms = connector->dpms;
        connector->dpms = mode;
@@ -258,7 +258,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode)
        crtc = encoder->base.crtc;
        if (!crtc) {
                encoder->connectors_active = false;
-               return;
+               return 0;
        }
 
        /* We need the pipe to run for anything but OFF. */
@@ -281,6 +281,8 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode)
        }
 
        intel_modeset_check_state(connector->dev);
+
+       return 0;
 }
 
 static enum drm_mode_status
index 40c73da2abcfd25db165c870a83b822b951b1e8d..13a6608be689830a52c3e891fd314e500ace7300 100644 (file)
@@ -6429,14 +6429,14 @@ struct intel_connector *intel_connector_alloc(void)
 
 /* Even simpler default implementation, if there's really no special case to
  * consider. */
-void intel_connector_dpms(struct drm_connector *connector, int mode)
+int intel_connector_dpms(struct drm_connector *connector, int mode)
 {
        /* All the simple cases only support two dpms states. */
        if (mode != DRM_MODE_DPMS_ON)
                mode = DRM_MODE_DPMS_OFF;
 
        if (mode == connector->dpms)
-               return;
+               return 0;
 
        connector->dpms = mode;
 
@@ -6445,6 +6445,8 @@ void intel_connector_dpms(struct drm_connector *connector, int mode)
                intel_encoder_dpms(to_intel_encoder(connector->encoder), mode);
 
        intel_modeset_check_state(connector->dev);
+
+       return 0;
 }
 
 /* Simple connector->get_hw_state implementation for encoders that support only
index 47cef0e6c79c985c3e1930ac02beb9eccac08d46..320c9e6bd8484e231767534e4563047957ff2b25 100644 (file)
@@ -997,7 +997,7 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc);
 void intel_encoder_destroy(struct drm_encoder *encoder);
 int intel_connector_init(struct intel_connector *);
 struct intel_connector *intel_connector_alloc(void);
-void intel_connector_dpms(struct drm_connector *, int mode);
+int intel_connector_dpms(struct drm_connector *, int mode);
 bool intel_connector_get_hw_state(struct intel_connector *connector);
 void intel_modeset_check_state(struct drm_device *dev);
 bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
index ece5bd754f85f5c0de25de036ba232ca19986b32..fd5e522abebb0c57e5fbdb71a64247915998a5dc 100644 (file)
@@ -197,7 +197,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
 }
 
 /* Special dpms function to support cloning between dvo/sdvo/crt. */
-static void intel_dvo_dpms(struct drm_connector *connector, int mode)
+static int intel_dvo_dpms(struct drm_connector *connector, int mode)
 {
        struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
        struct drm_crtc *crtc;
@@ -208,7 +208,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
                mode = DRM_MODE_DPMS_OFF;
 
        if (mode == connector->dpms)
-               return;
+               return 0;
 
        connector->dpms = mode;
 
@@ -216,7 +216,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
        crtc = intel_dvo->base.base.crtc;
        if (!crtc) {
                intel_dvo->base.connectors_active = false;
-               return;
+               return 0;
        }
 
        /* We call connector dpms manually below in case pipe dpms doesn't
@@ -238,6 +238,8 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
        }
 
        intel_modeset_check_state(connector->dev);
+
+       return 0;
 }
 
 static enum drm_mode_status
index aa2fd751609cf2be92826d4f8e6ba85df971892e..2c435a79d4da32c29619e5ef960d08959ebfb3ef 100644 (file)
@@ -1509,7 +1509,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
 }
 
 /* Special dpms function to support cloning between dvo/sdvo/crt. */
-static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
+static int intel_sdvo_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_crtc *crtc;
        struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
@@ -1519,7 +1519,7 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
                mode = DRM_MODE_DPMS_OFF;
 
        if (mode == connector->dpms)
-               return;
+               return 0;
 
        connector->dpms = mode;
 
@@ -1527,7 +1527,7 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
        crtc = intel_sdvo->base.base.crtc;
        if (!crtc) {
                intel_sdvo->base.connectors_active = false;
-               return;
+               return 0;
        }
 
        /* We set active outputs manually below in case pipe dpms doesn't change
@@ -1551,6 +1551,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
        }
 
        intel_modeset_check_state(connector->dev);
+
+       return 0;
 }
 
 static enum drm_mode_status
index 3162040bc3148b2157249dd29f945d8d05585812..1f26eba245d10b624ecdbab392ed7ef30f0d163d 100644 (file)
@@ -919,7 +919,7 @@ nouveau_connector_funcs_lvds = {
        .force = nouveau_connector_force
 };
 
-static void
+static int
 nouveau_connector_dp_dpms(struct drm_connector *connector, int mode)
 {
        struct nouveau_encoder *nv_encoder = NULL;
@@ -938,7 +938,7 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode)
                }
        }
 
-       drm_helper_connector_dpms(connector, mode);
+       return drm_helper_connector_dpms(connector, mode);
 }
 
 static const struct drm_connector_funcs
index e4fc8f3bf58b09175c0d1dc868b2ce52327c4c18..5e09c061847f50c688650d12625a462e8c4737cd 100644 (file)
@@ -246,9 +246,10 @@ radeon_dp_mst_connector_destroy(struct drm_connector *connector)
        kfree(radeon_connector);
 }
 
-static void radeon_connector_dpms(struct drm_connector *connector, int mode)
+static int radeon_connector_dpms(struct drm_connector *connector, int mode)
 {
        DRM_DEBUG_KMS("\n");
+       return 0;
 }
 
 static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = {
index ed970f62290306e5c78158f9600211d51251dc78..dc97c0b3681d95d60c6b983c29afd036c7aa14f5 100644 (file)
@@ -726,8 +726,9 @@ static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
                tegra_dsi_soft_reset(dsi->slave);
 }
 
-static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode)
+static int tegra_dsi_connector_dpms(struct drm_connector *connector, int mode)
 {
+       return 0;
 }
 
 static void tegra_dsi_connector_reset(struct drm_connector *connector)
index 06ab1783bba11e7b1299e3d950accf1547e20285..fe4008a7ddba56695439bafd5c3e185e34d766ad 100644 (file)
@@ -772,9 +772,10 @@ static bool tegra_output_is_hdmi(struct tegra_output *output)
        return drm_detect_hdmi_monitor(edid);
 }
 
-static void tegra_hdmi_connector_dpms(struct drm_connector *connector,
-                                     int mode)
+static int tegra_hdmi_connector_dpms(struct drm_connector *connector,
+                                    int mode)
 {
+       return 0;
 }
 
 static const struct drm_connector_funcs tegra_hdmi_connector_funcs = {
index 7cd833f5b5b591257da40c04efc209057ec62549..9a99d213e1b1e8aeb2481771aac46c4a3fa2b3b6 100644 (file)
@@ -88,9 +88,10 @@ static void tegra_dc_write_regs(struct tegra_dc *dc,
                tegra_dc_writel(dc, table[i].value, table[i].offset);
 }
 
-static void tegra_rgb_connector_dpms(struct drm_connector *connector,
-                                    int mode)
+static int tegra_rgb_connector_dpms(struct drm_connector *connector,
+                                   int mode)
 {
+       return 0;
 }
 
 static const struct drm_connector_funcs tegra_rgb_connector_funcs = {
index 7591d8901f9a24ddd61d035500116c617e4df3f6..ee8ad0d4a0f28700ab54d663716cc37889ef7034 100644 (file)
@@ -866,8 +866,9 @@ static void tegra_sor_debugfs_exit(struct tegra_sor *sor)
        sor->debugfs_files = NULL;
 }
 
-static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode)
+static int tegra_sor_connector_dpms(struct drm_connector *connector, int mode)
 {
+       return 0;
 }
 
 static enum drm_connector_status
index 07cda8cbbddbcb5e6f56127c57dac0e683541fb9..2adc11bc09209cee810eae29b807c7c0e89be2bd 100644 (file)
@@ -1808,8 +1808,9 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
        }
 }
 
-void vmw_du_connector_dpms(struct drm_connector *connector, int mode)
+int vmw_du_connector_dpms(struct drm_connector *connector, int mode)
 {
+       return 0;
 }
 
 void vmw_du_connector_save(struct drm_connector *connector)
index 8d038c36bd57599b311f129532a768e9d39fdfa0..f1a324cfb4c3008b1b8ad9db8a17604fa683ea3d 100644 (file)
@@ -133,7 +133,7 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
 int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
                           uint32_t handle, uint32_t width, uint32_t height);
 int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
-void vmw_du_connector_dpms(struct drm_connector *connector, int mode);
+int vmw_du_connector_dpms(struct drm_connector *connector, int mode);
 void vmw_du_connector_save(struct drm_connector *connector);
 void vmw_du_connector_restore(struct drm_connector *connector);
 enum drm_connector_status
index cc1fee8a12d0a5e71babb3626644604618b987ba..11266d147a29409b12718a1b575520579d588fde 100644 (file)
@@ -87,8 +87,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
                                struct drm_pending_vblank_event *event,
                                uint32_t flags);
-void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
-                                     int mode);
+int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+                                    int mode);
 
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
index 90a0ff70384a4df5e69839bbe23b664517dec4f9..5746569651263dc938b9ee7abeede90ce48ea301 100644 (file)
@@ -527,7 +527,7 @@ struct drm_connector_state {
  * etc.
  */
 struct drm_connector_funcs {
-       void (*dpms)(struct drm_connector *connector, int mode);
+       int (*dpms)(struct drm_connector *connector, int mode);
        void (*save)(struct drm_connector *connector);
        void (*restore)(struct drm_connector *connector);
        void (*reset)(struct drm_connector *connector);
index 01cafcbe7deb5faef7497aae67e49b8dbee39512..800e0d1cf32c2a397932a7597384350fd08a2f94 100644 (file)
@@ -189,7 +189,7 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
 extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
 
-extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode);
+extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode);
 
 extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);