Commit f9885ef8 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-intel-next-fixes-2018-10-25' of...

Merge tag 'drm-intel-next-fixes-2018-10-25' of git://anongit.freedesktop.org/drm/drm-intel into drm-next

- Fix to avoid link retraining workaround on eDP (the other is a comment change)
Signed-off-by: default avatarDave 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
parents 43e0f873 f9776280
...@@ -308,6 +308,26 @@ update_connector_routing(struct drm_atomic_state *state, ...@@ -308,6 +308,26 @@ update_connector_routing(struct drm_atomic_state *state,
return 0; 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; funcs = connector->helper_private;
if (funcs->atomic_best_encoder) if (funcs->atomic_best_encoder)
...@@ -352,7 +372,6 @@ update_connector_routing(struct drm_atomic_state *state, ...@@ -352,7 +372,6 @@ update_connector_routing(struct drm_atomic_state *state,
set_best_encoder(state, new_connector_state, new_encoder); 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; crtc_state->connectors_changed = true;
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n", DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
......
...@@ -379,7 +379,8 @@ void drm_connector_cleanup(struct drm_connector *connector) ...@@ -379,7 +379,8 @@ void drm_connector_cleanup(struct drm_connector *connector)
/* The connector should have been removed from userspace long before /* The connector should have been removed from userspace long before
* it is finally destroyed. * it is finally destroyed.
*/ */
if (WARN_ON(connector->registered)) if (WARN_ON(connector->registration_state ==
DRM_CONNECTOR_REGISTERED))
drm_connector_unregister(connector); drm_connector_unregister(connector);
if (connector->tile_group) { if (connector->tile_group) {
...@@ -436,7 +437,7 @@ int drm_connector_register(struct drm_connector *connector) ...@@ -436,7 +437,7 @@ int drm_connector_register(struct drm_connector *connector)
return 0; return 0;
mutex_lock(&connector->mutex); mutex_lock(&connector->mutex);
if (connector->registered) if (connector->registration_state != DRM_CONNECTOR_INITIALIZING)
goto unlock; goto unlock;
ret = drm_sysfs_connector_add(connector); ret = drm_sysfs_connector_add(connector);
...@@ -456,7 +457,7 @@ int drm_connector_register(struct drm_connector *connector) ...@@ -456,7 +457,7 @@ int drm_connector_register(struct drm_connector *connector)
drm_mode_object_register(connector->dev, &connector->base); drm_mode_object_register(connector->dev, &connector->base);
connector->registered = true; connector->registration_state = DRM_CONNECTOR_REGISTERED;
goto unlock; goto unlock;
err_debugfs: err_debugfs:
...@@ -478,7 +479,7 @@ EXPORT_SYMBOL(drm_connector_register); ...@@ -478,7 +479,7 @@ EXPORT_SYMBOL(drm_connector_register);
void drm_connector_unregister(struct drm_connector *connector) void drm_connector_unregister(struct drm_connector *connector)
{ {
mutex_lock(&connector->mutex); mutex_lock(&connector->mutex);
if (!connector->registered) { if (connector->registration_state != DRM_CONNECTOR_REGISTERED) {
mutex_unlock(&connector->mutex); mutex_unlock(&connector->mutex);
return; return;
} }
...@@ -489,7 +490,7 @@ void drm_connector_unregister(struct drm_connector *connector) ...@@ -489,7 +490,7 @@ void drm_connector_unregister(struct drm_connector *connector)
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
drm_debugfs_connector_remove(connector); drm_debugfs_connector_remove(connector);
connector->registered = false; connector->registration_state = DRM_CONNECTOR_UNREGISTERED;
mutex_unlock(&connector->mutex); mutex_unlock(&connector->mutex);
} }
EXPORT_SYMBOL(drm_connector_unregister); EXPORT_SYMBOL(drm_connector_unregister);
......
...@@ -5102,19 +5102,13 @@ intel_dp_long_pulse(struct intel_connector *connector, ...@@ -5102,19 +5102,13 @@ intel_dp_long_pulse(struct intel_connector *connector,
*/ */
status = connector_status_disconnected; status = connector_status_disconnected;
goto out; goto out;
} else { }
/*
* If display is now connected check links status, /*
* there has been known issues of link loss triggering * Some external monitors do not signal loss of link synchronization
* long pulse. * with an IRQ_HPD, so force a link status check.
* */
* Some sinks (eg. ASUS PB287Q) seem to perform some if (!intel_dp_is_edp(intel_dp)) {
* 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.
*/
struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
intel_dp_retrain_link(encoder, ctx); intel_dp_retrain_link(encoder, ctx);
......
...@@ -77,7 +77,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, ...@@ -77,7 +77,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
pipe_config->pbn = mst_pbn; pipe_config->pbn = mst_pbn;
/* Zombie connectors can't have VCPI slots */ /* 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, slots = drm_dp_atomic_find_vcpi_slots(state,
&intel_dp->mst_mgr, &intel_dp->mst_mgr,
port, port,
...@@ -313,7 +313,7 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector) ...@@ -313,7 +313,7 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
struct edid *edid; struct edid *edid;
int ret; int ret;
if (!READ_ONCE(connector->registered)) if (drm_connector_is_unregistered(connector))
return intel_connector_update_modes(connector, NULL); return intel_connector_update_modes(connector, NULL);
edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); 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) ...@@ -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_connector *intel_connector = to_intel_connector(connector);
struct intel_dp *intel_dp = intel_connector->mst_port; 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 connector_status_disconnected;
return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr,
intel_connector->port); intel_connector->port);
...@@ -372,7 +372,7 @@ intel_dp_mst_mode_valid(struct drm_connector *connector, ...@@ -372,7 +372,7 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
int bpp = 24; /* MST uses fixed bpp */ int bpp = 24; /* MST uses fixed bpp */
int max_rate, mode_rate, max_lanes, max_link_clock; int max_rate, mode_rate, max_lanes, max_link_clock;
if (!READ_ONCE(connector->registered)) if (drm_connector_is_unregistered(connector))
return MODE_ERROR; return MODE_ERROR;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN) if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
......
...@@ -881,22 +881,16 @@ nv50_mstc_atomic_best_encoder(struct drm_connector *connector, ...@@ -881,22 +881,16 @@ nv50_mstc_atomic_best_encoder(struct drm_connector *connector,
{ {
struct nv50_head *head = nv50_head(connector_state->crtc); struct nv50_head *head = nv50_head(connector_state->crtc);
struct nv50_mstc *mstc = nv50_mstc(connector); struct nv50_mstc *mstc = nv50_mstc(connector);
if (mstc->port) {
struct nv50_mstm *mstm = mstc->mstm; return &mstc->mstm->msto[head->base.index]->encoder;
return &mstm->msto[head->base.index]->encoder;
}
return NULL;
} }
static struct drm_encoder * static struct drm_encoder *
nv50_mstc_best_encoder(struct drm_connector *connector) nv50_mstc_best_encoder(struct drm_connector *connector)
{ {
struct nv50_mstc *mstc = nv50_mstc(connector); struct nv50_mstc *mstc = nv50_mstc(connector);
if (mstc->port) {
struct nv50_mstm *mstm = mstc->mstm; return &mstc->mstm->msto[0]->encoder;
return &mstm->msto[0]->encoder;
}
return NULL;
} }
static enum drm_mode_status static enum drm_mode_status
......
...@@ -82,6 +82,53 @@ enum drm_connector_status { ...@@ -82,6 +82,53 @@ enum drm_connector_status {
connector_status_unknown = 3, 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 { enum subpixel_order {
SubPixelUnknown = 0, SubPixelUnknown = 0,
SubPixelHorizontalRGB, SubPixelHorizontalRGB,
...@@ -853,10 +900,12 @@ struct drm_connector { ...@@ -853,10 +900,12 @@ struct drm_connector {
bool ycbcr_420_allowed; 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. * Protected by @mutex.
*/ */
bool registered; enum drm_connector_registration_state registration_state;
/** /**
* @modes: * @modes:
...@@ -1166,6 +1215,24 @@ static inline void drm_connector_unreference(struct drm_connector *connector) ...@@ -1166,6 +1215,24 @@ static inline void drm_connector_unreference(struct drm_connector *connector)
drm_connector_put(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_connector_status_name(enum drm_connector_status status);
const char *drm_get_subpixel_order_name(enum subpixel_order order); const char *drm_get_subpixel_order_name(enum subpixel_order order);
const char *drm_get_dpms_name(int val); const char *drm_get_dpms_name(int val);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment