drm: Use a nondestructive mode for output detect when polling
Destructive load-detection is very expensive and due to failings elsewhere can trigger system wide stalls of up to 600ms. A simple first step to correcting this is not to invoke such an expensive and destructive load-detection operation automatically. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29536 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16265 Reported-by: Bruno Prémont <bonbons@linux-vserver.org> Tested-by: Sitsofe Wheeler <sitsofe@yahoo.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
27849044ca
commit
7b334fcb45
|
@ -103,7 +103,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||||
if (connector->funcs->force)
|
if (connector->funcs->force)
|
||||||
connector->funcs->force(connector);
|
connector->funcs->force(connector);
|
||||||
} else {
|
} else {
|
||||||
connector->status = connector->funcs->detect(connector);
|
connector->status = connector->funcs->detect(connector, false);
|
||||||
drm_kms_helper_poll_enable(dev);
|
drm_kms_helper_poll_enable(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,7 +866,7 @@ static void output_poll_execute(struct work_struct *work)
|
||||||
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
|
!(connector->polled & DRM_CONNECTOR_POLL_HPD))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
status = connector->funcs->detect(connector);
|
status = connector->funcs->detect(connector, true);
|
||||||
if (old_status != status)
|
if (old_status != status)
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ static ssize_t status_show(struct device *device,
|
||||||
struct drm_connector *connector = to_drm_connector(device);
|
struct drm_connector *connector = to_drm_connector(device);
|
||||||
enum drm_connector_status status;
|
enum drm_connector_status status;
|
||||||
|
|
||||||
status = connector->funcs->detect(connector);
|
status = connector->funcs->detect(connector, true);
|
||||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||||
drm_get_connector_status_name(status));
|
drm_get_connector_status_name(status));
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,7 +400,9 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
intel_crt_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||||
|
@ -419,6 +421,9 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto
|
||||||
if (intel_crt_detect_ddc(encoder))
|
if (intel_crt_detect_ddc(encoder))
|
||||||
return connector_status_connected;
|
return connector_status_connected;
|
||||||
|
|
||||||
|
if (nondestructive)
|
||||||
|
return connector->status;
|
||||||
|
|
||||||
/* for pre-945g platforms use load detect */
|
/* for pre-945g platforms use load detect */
|
||||||
if (encoder->crtc && encoder->crtc->enabled) {
|
if (encoder->crtc && encoder->crtc->enabled) {
|
||||||
status = intel_crt_load_detect(encoder->crtc, intel_encoder);
|
status = intel_crt_load_detect(encoder->crtc, intel_encoder);
|
||||||
|
|
|
@ -1386,7 +1386,8 @@ ironlake_dp_detect(struct drm_connector *connector)
|
||||||
* \return false if DP port is disconnected.
|
* \return false if DP port is disconnected.
|
||||||
*/
|
*/
|
||||||
static enum drm_connector_status
|
static enum drm_connector_status
|
||||||
intel_dp_detect(struct drm_connector *connector)
|
intel_dp_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||||
|
|
|
@ -221,7 +221,9 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
|
||||||
*
|
*
|
||||||
* Unimplemented.
|
* Unimplemented.
|
||||||
*/
|
*/
|
||||||
static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
intel_dvo_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||||
struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
|
struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
|
||||||
|
|
|
@ -139,7 +139,8 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status
|
static enum drm_connector_status
|
||||||
intel_hdmi_detect(struct drm_connector *connector)
|
intel_hdmi_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||||
|
|
|
@ -445,7 +445,9 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
|
||||||
* connected and closed means disconnected. We also send hotplug events as
|
* connected and closed means disconnected. We also send hotplug events as
|
||||||
* needed, using lid status notification from the input layer.
|
* needed, using lid status notification from the input layer.
|
||||||
*/
|
*/
|
||||||
static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
intel_lvds_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
enum drm_connector_status status = connector_status_connected;
|
enum drm_connector_status status = connector_status_connected;
|
||||||
|
@ -540,7 +542,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
|
||||||
* the LID nofication event.
|
* the LID nofication event.
|
||||||
*/
|
*/
|
||||||
if (connector)
|
if (connector)
|
||||||
connector->status = connector->funcs->detect(connector);
|
connector->status = connector->funcs->detect(connector,
|
||||||
|
true);
|
||||||
|
|
||||||
/* Don't force modeset on machines where it causes a GPU lockup */
|
/* Don't force modeset on machines where it causes a GPU lockup */
|
||||||
if (dmi_check_system(intel_no_modeset_on_lid))
|
if (dmi_check_system(intel_no_modeset_on_lid))
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
|
|
|
@ -1417,7 +1417,7 @@ intel_analog_is_connected(struct drm_device *dev)
|
||||||
if (!analog_connector)
|
if (!analog_connector)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (analog_connector->funcs->detect(analog_connector) ==
|
if (analog_connector->funcs->detect(analog_connector, true) ==
|
||||||
connector_status_disconnected)
|
connector_status_disconnected)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1486,7 +1486,9 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
intel_sdvo_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
uint16_t response;
|
uint16_t response;
|
||||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||||
|
|
|
@ -1341,7 +1341,8 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
|
||||||
* we have a pipe programmed in order to probe the TV.
|
* we have a pipe programmed in order to probe the TV.
|
||||||
*/
|
*/
|
||||||
static enum drm_connector_status
|
static enum drm_connector_status
|
||||||
intel_tv_detect(struct drm_connector *connector)
|
intel_tv_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_display_mode mode;
|
struct drm_display_mode mode;
|
||||||
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
struct drm_encoder *encoder = intel_attached_encoder(connector);
|
||||||
|
@ -1353,7 +1354,7 @@ intel_tv_detect(struct drm_connector *connector)
|
||||||
|
|
||||||
if (encoder->crtc && encoder->crtc->enabled) {
|
if (encoder->crtc && encoder->crtc->enabled) {
|
||||||
type = intel_tv_detect_type(intel_tv);
|
type = intel_tv_detect_type(intel_tv);
|
||||||
} else {
|
} else if (nondestructive) {
|
||||||
struct drm_crtc *crtc;
|
struct drm_crtc *crtc;
|
||||||
int dpms_mode;
|
int dpms_mode;
|
||||||
|
|
||||||
|
@ -1364,10 +1365,9 @@ intel_tv_detect(struct drm_connector *connector)
|
||||||
intel_release_load_detect_pipe(&intel_tv->base, connector,
|
intel_release_load_detect_pipe(&intel_tv->base, connector,
|
||||||
dpms_mode);
|
dpms_mode);
|
||||||
} else
|
} else
|
||||||
type = -1;
|
return connector_status_unknown;
|
||||||
}
|
} else
|
||||||
|
return connector->status;
|
||||||
intel_tv->type = type;
|
|
||||||
|
|
||||||
if (type < 0)
|
if (type < 0)
|
||||||
return connector_status_disconnected;
|
return connector_status_disconnected;
|
||||||
|
|
|
@ -168,7 +168,8 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status
|
static enum drm_connector_status
|
||||||
nouveau_connector_detect(struct drm_connector *connector)
|
nouveau_connector_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||||
|
@ -246,7 +247,8 @@ detect_analog:
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status
|
static enum drm_connector_status
|
||||||
nouveau_connector_detect_lvds(struct drm_connector *connector)
|
nouveau_connector_detect_lvds(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||||
|
@ -267,7 +269,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector)
|
||||||
|
|
||||||
/* Try retrieving EDID via DDC */
|
/* Try retrieving EDID via DDC */
|
||||||
if (!dev_priv->vbios.fp_no_ddc) {
|
if (!dev_priv->vbios.fp_no_ddc) {
|
||||||
status = nouveau_connector_detect(connector);
|
status = nouveau_connector_detect(connector, nondestructive);
|
||||||
if (status == connector_status_connected)
|
if (status == connector_status_connected)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -481,7 +481,9 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector,
|
||||||
return MODE_OK;
|
return MODE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
radeon_lvds_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||||
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
|
struct drm_encoder *encoder = radeon_best_single_encoder(connector);
|
||||||
|
@ -594,7 +596,9 @@ static int radeon_vga_mode_valid(struct drm_connector *connector,
|
||||||
return MODE_OK;
|
return MODE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
radeon_vga_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
|
@ -691,7 +695,9 @@ static int radeon_tv_mode_valid(struct drm_connector *connector,
|
||||||
return MODE_OK;
|
return MODE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
radeon_tv_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||||
|
@ -748,7 +754,9 @@ static int radeon_dvi_get_modes(struct drm_connector *connector)
|
||||||
* we have to check if this analog encoder is shared with anyone else (TV)
|
* we have to check if this analog encoder is shared with anyone else (TV)
|
||||||
* if its shared we have to set the other connector to disconnected.
|
* if its shared we have to set the other connector to disconnected.
|
||||||
*/
|
*/
|
||||||
static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
radeon_dvi_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||||
struct drm_encoder *encoder = NULL;
|
struct drm_encoder *encoder = NULL;
|
||||||
|
@ -972,7 +980,9 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status radeon_dp_detect(struct drm_connector *connector)
|
static enum drm_connector_status
|
||||||
|
radeon_dp_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
|
||||||
enum drm_connector_status ret = connector_status_disconnected;
|
enum drm_connector_status ret = connector_status_disconnected;
|
||||||
|
|
|
@ -335,7 +335,8 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector)
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum drm_connector_status
|
static enum drm_connector_status
|
||||||
vmw_ldu_connector_detect(struct drm_connector *connector)
|
vmw_ldu_connector_detect(struct drm_connector *connector,
|
||||||
|
bool nondestructive)
|
||||||
{
|
{
|
||||||
if (vmw_connector_to_ldu(connector)->pref_active)
|
if (vmw_connector_to_ldu(connector)->pref_active)
|
||||||
return connector_status_connected;
|
return connector_status_connected;
|
||||||
|
|
|
@ -386,7 +386,8 @@ struct drm_connector_funcs {
|
||||||
void (*dpms)(struct drm_connector *connector, int mode);
|
void (*dpms)(struct drm_connector *connector, int mode);
|
||||||
void (*save)(struct drm_connector *connector);
|
void (*save)(struct drm_connector *connector);
|
||||||
void (*restore)(struct drm_connector *connector);
|
void (*restore)(struct drm_connector *connector);
|
||||||
enum drm_connector_status (*detect)(struct drm_connector *connector);
|
enum drm_connector_status (*detect)(struct drm_connector *connector,
|
||||||
|
bool nondestructive);
|
||||||
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
|
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
|
||||||
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
|
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
|
||||||
uint64_t val);
|
uint64_t val);
|
||||||
|
|
Loading…
Reference in New Issue