Merge tag 'drm-intel-next-fixes-2018-10-25' of git://anongit.freedesktop.org/drm...
authorDave Airlie <airlied@redhat.com>
Fri, 2 Nov 2018 05:17:56 +0000 (15:17 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 2 Nov 2018 05:17:57 +0000 (15:17 +1000)
- Fix to avoid link retraining workaround on eDP (the other is a comment change)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181025131836.GA2296@jlahtine-desk.ger.corp.intel.com
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/nouveau/dispnv50/disp.c
include/drm/drm_connector.h

index e49b22381048a912000b71f26d8f8bb6cf3d9a65..1cc3a045ec2f15570aeb96d70e8d70eee4c22a5a 100644 (file)
@@ -308,6 +308,26 @@ update_connector_routing(struct drm_atomic_state *state,
                return 0;
        }
 
+       crtc_state = drm_atomic_get_new_crtc_state(state,
+                                                  new_connector_state->crtc);
+       /*
+        * For compatibility with legacy users, we want to make sure that
+        * we allow DPMS On->Off modesets on unregistered connectors. Modesets
+        * which would result in anything else must be considered invalid, to
+        * avoid turning on new displays on dead connectors.
+        *
+        * Since the connector can be unregistered at any point during an
+        * atomic check or commit, this is racy. But that's OK: all we care
+        * about is ensuring that userspace can't do anything but shut off the
+        * display on a connector that was destroyed after its been notified,
+        * not before.
+        */
+       if (drm_connector_is_unregistered(connector) && crtc_state->active) {
+               DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n",
+                                connector->base.id, connector->name);
+               return -EINVAL;
+       }
+
        funcs = connector->helper_private;
 
        if (funcs->atomic_best_encoder)
@@ -352,7 +372,6 @@ update_connector_routing(struct drm_atomic_state *state,
 
        set_best_encoder(state, new_connector_state, new_encoder);
 
-       crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc);
        crtc_state->connectors_changed = true;
 
        DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
index 1e40e5decbe91a4f709305d5259b5b7c0425e617..4943cef178beb7675ab46a0d3100e33ae836bd0e 100644 (file)
@@ -379,7 +379,8 @@ void drm_connector_cleanup(struct drm_connector *connector)
        /* The connector should have been removed from userspace long before
         * it is finally destroyed.
         */
-       if (WARN_ON(connector->registered))
+       if (WARN_ON(connector->registration_state ==
+                   DRM_CONNECTOR_REGISTERED))
                drm_connector_unregister(connector);
 
        if (connector->tile_group) {
@@ -436,7 +437,7 @@ int drm_connector_register(struct drm_connector *connector)
                return 0;
 
        mutex_lock(&connector->mutex);
-       if (connector->registered)
+       if (connector->registration_state != DRM_CONNECTOR_INITIALIZING)
                goto unlock;
 
        ret = drm_sysfs_connector_add(connector);
@@ -456,7 +457,7 @@ int drm_connector_register(struct drm_connector *connector)
 
        drm_mode_object_register(connector->dev, &connector->base);
 
-       connector->registered = true;
+       connector->registration_state = DRM_CONNECTOR_REGISTERED;
        goto unlock;
 
 err_debugfs:
@@ -478,7 +479,7 @@ EXPORT_SYMBOL(drm_connector_register);
 void drm_connector_unregister(struct drm_connector *connector)
 {
        mutex_lock(&connector->mutex);
-       if (!connector->registered) {
+       if (connector->registration_state != DRM_CONNECTOR_REGISTERED) {
                mutex_unlock(&connector->mutex);
                return;
        }
@@ -489,7 +490,7 @@ void drm_connector_unregister(struct drm_connector *connector)
        drm_sysfs_connector_remove(connector);
        drm_debugfs_connector_remove(connector);
 
-       connector->registered = false;
+       connector->registration_state = DRM_CONNECTOR_UNREGISTERED;
        mutex_unlock(&connector->mutex);
 }
 EXPORT_SYMBOL(drm_connector_unregister);
index 3fae4dab295f093892491ecd010970dc7fc28128..13f9b56a9ce7ca711467fc9309b720f8d9565661 100644 (file)
@@ -5102,19 +5102,13 @@ intel_dp_long_pulse(struct intel_connector *connector,
                 */
                status = connector_status_disconnected;
                goto out;
-       } else {
-               /*
-                * If display is now connected check links status,
-                * there has been known issues of link loss triggering
-                * long pulse.
-                *
-                * Some sinks (eg. ASUS PB287Q) seem to perform some
-                * weird HPD ping pong during modesets. So we can apparently
-                * end up with HPD going low during a modeset, and then
-                * going back up soon after. And once that happens we must
-                * retrain the link to get a picture. That's in case no
-                * userspace component reacted to intermittent HPD dip.
-                */
+       }
+
+       /*
+        * Some external monitors do not signal loss of link synchronization
+        * with an IRQ_HPD, so force a link status check.
+        */
+       if (!intel_dp_is_edp(intel_dp)) {
                struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
 
                intel_dp_retrain_link(encoder, ctx);
index 7f155b4f1a7d7ab9a3389181d411140951962d6e..1b00f8ea145ba3990d17f6e7142755bae8ca6a77 100644 (file)
@@ -77,7 +77,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
        pipe_config->pbn = mst_pbn;
 
        /* Zombie connectors can't have VCPI slots */
-       if (READ_ONCE(connector->registered)) {
+       if (!drm_connector_is_unregistered(connector)) {
                slots = drm_dp_atomic_find_vcpi_slots(state,
                                                      &intel_dp->mst_mgr,
                                                      port,
@@ -313,7 +313,7 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
        struct edid *edid;
        int ret;
 
-       if (!READ_ONCE(connector->registered))
+       if (drm_connector_is_unregistered(connector))
                return intel_connector_update_modes(connector, NULL);
 
        edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port);
@@ -329,7 +329,7 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force)
        struct intel_connector *intel_connector = to_intel_connector(connector);
        struct intel_dp *intel_dp = intel_connector->mst_port;
 
-       if (!READ_ONCE(connector->registered))
+       if (drm_connector_is_unregistered(connector))
                return connector_status_disconnected;
        return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr,
                                      intel_connector->port);
@@ -372,7 +372,7 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
        int bpp = 24; /* MST uses fixed bpp */
        int max_rate, mode_rate, max_lanes, max_link_clock;
 
-       if (!READ_ONCE(connector->registered))
+       if (drm_connector_is_unregistered(connector))
                return MODE_ERROR;
 
        if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
index 5f163a025e8906b671f653df46c14b4387fe6b3f..9d9a18ab95ecec4eb1030d9da471d84923c39ac6 100644 (file)
@@ -881,22 +881,16 @@ nv50_mstc_atomic_best_encoder(struct drm_connector *connector,
 {
        struct nv50_head *head = nv50_head(connector_state->crtc);
        struct nv50_mstc *mstc = nv50_mstc(connector);
-       if (mstc->port) {
-               struct nv50_mstm *mstm = mstc->mstm;
-               return &mstm->msto[head->base.index]->encoder;
-       }
-       return NULL;
+
+       return &mstc->mstm->msto[head->base.index]->encoder;
 }
 
 static struct drm_encoder *
 nv50_mstc_best_encoder(struct drm_connector *connector)
 {
        struct nv50_mstc *mstc = nv50_mstc(connector);
-       if (mstc->port) {
-               struct nv50_mstm *mstm = mstc->mstm;
-               return &mstm->msto[0]->encoder;
-       }
-       return NULL;
+
+       return &mstc->mstm->msto[0]->encoder;
 }
 
 static enum drm_mode_status
index 91a877fa00cb59161125a711515931e49b040e53..9ccad6b062f2bb62c54434288e7fc9a25b194b53 100644 (file)
@@ -82,6 +82,53 @@ enum drm_connector_status {
        connector_status_unknown = 3,
 };
 
+/**
+ * enum drm_connector_registration_status - userspace registration status for
+ * a &drm_connector
+ *
+ * This enum is used to track the status of initializing a connector and
+ * registering it with userspace, so that DRM can prevent bogus modesets on
+ * connectors that no longer exist.
+ */
+enum drm_connector_registration_state {
+       /**
+        * @DRM_CONNECTOR_INITIALIZING: The connector has just been created,
+        * but has yet to be exposed to userspace. There should be no
+        * additional restrictions to how the state of this connector may be
+        * modified.
+        */
+       DRM_CONNECTOR_INITIALIZING = 0,
+
+       /**
+        * @DRM_CONNECTOR_REGISTERED: The connector has been fully initialized
+        * and registered with sysfs, as such it has been exposed to
+        * userspace. There should be no additional restrictions to how the
+        * state of this connector may be modified.
+        */
+       DRM_CONNECTOR_REGISTERED = 1,
+
+       /**
+        * @DRM_CONNECTOR_UNREGISTERED: The connector has either been exposed
+        * to userspace and has since been unregistered and removed from
+        * userspace, or the connector was unregistered before it had a chance
+        * to be exposed to userspace (e.g. still in the
+        * @DRM_CONNECTOR_INITIALIZING state). When a connector is
+        * unregistered, there are additional restrictions to how its state
+        * may be modified:
+        *
+        * - An unregistered connector may only have its DPMS changed from
+        *   On->Off. Once DPMS is changed to Off, it may not be switched back
+        *   to On.
+        * - Modesets are not allowed on unregistered connectors, unless they
+        *   would result in disabling its assigned CRTCs. This means
+        *   disabling a CRTC on an unregistered connector is OK, but enabling
+        *   one is not.
+        * - Removing a CRTC from an unregistered connector is OK, but new
+        *   CRTCs may never be assigned to an unregistered connector.
+        */
+       DRM_CONNECTOR_UNREGISTERED = 2,
+};
+
 enum subpixel_order {
        SubPixelUnknown = 0,
        SubPixelHorizontalRGB,
@@ -853,10 +900,12 @@ struct drm_connector {
        bool ycbcr_420_allowed;
 
        /**
-        * @registered: Is this connector exposed (registered) with userspace?
+        * @registration_state: Is this connector initializing, exposed
+        * (registered) with userspace, or unregistered?
+        *
         * Protected by @mutex.
         */
-       bool registered;
+       enum drm_connector_registration_state registration_state;
 
        /**
         * @modes:
@@ -1166,6 +1215,24 @@ static inline void drm_connector_unreference(struct drm_connector *connector)
        drm_connector_put(connector);
 }
 
+/**
+ * drm_connector_is_unregistered - has the connector been unregistered from
+ * userspace?
+ * @connector: DRM connector
+ *
+ * Checks whether or not @connector has been unregistered from userspace.
+ *
+ * Returns:
+ * True if the connector was unregistered, false if the connector is
+ * registered or has not yet been registered with userspace.
+ */
+static inline bool
+drm_connector_is_unregistered(struct drm_connector *connector)
+{
+       return READ_ONCE(connector->registration_state) ==
+               DRM_CONNECTOR_UNREGISTERED;
+}
+
 const char *drm_get_connector_status_name(enum drm_connector_status status);
 const char *drm_get_subpixel_order_name(enum subpixel_order order);
 const char *drm_get_dpms_name(int val);