Commit 6c5ed5ae authored by Maarten Lankhorst's avatar Maarten Lankhorst

drm/atomic: Acquire connection_mutex lock in drm_helper_probe_single_connector_modes, v4.

mode_valid() called from drm_helper_probe_single_connector_modes()
may need to look at connector->state because what a valid mode is may
depend on connector properties being set. For example some HDMI modes
might be rejected when a connector property forces the connector
into DVI mode.

Some implementations of detect() already lock all state,
so we have to pass an acquire_ctx to them to prevent a deadlock.

This means changing the function signature of detect() slightly,
and passing the acquire_ctx for locking multiple crtc's.
For the callbacks, it will always be non-zero. To allow callers
not to worry about this, drm_helper_probe_detect_ctx is added
which might handle -EDEADLK for you.

Changes since v1:
- Always set ctx parameter.
Changes since v2:
- Always take connection_mutex when probing.
Changes since v3:
- Remove the ctx from intel_dp_long_pulse, and add
  WARN_ON(!connection_mutex) (danvet)
- Update docs to clarify the locking situation. (danvet)
Signed-off-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1491504920-4017-1-git-send-email-maarten.lankhorst@linux.intel.com
parent 99748ab6
...@@ -169,12 +169,73 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) ...@@ -169,12 +169,73 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
EXPORT_SYMBOL(drm_kms_helper_poll_enable); EXPORT_SYMBOL(drm_kms_helper_poll_enable);
static enum drm_connector_status static enum drm_connector_status
drm_connector_detect(struct drm_connector *connector, bool force) drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
{ {
return connector->funcs->detect ? const struct drm_connector_helper_funcs *funcs = connector->helper_private;
connector->funcs->detect(connector, force) : struct drm_modeset_acquire_ctx ctx;
connector_status_connected; int ret;
drm_modeset_acquire_init(&ctx, 0);
retry:
ret = drm_modeset_lock(&connector->dev->mode_config.connection_mutex, &ctx);
if (!ret) {
if (funcs->detect_ctx)
ret = funcs->detect_ctx(connector, &ctx, force);
else if (connector->funcs->detect)
ret = connector->funcs->detect(connector, force);
else
ret = connector_status_connected;
}
if (ret == -EDEADLK) {
drm_modeset_backoff(&ctx);
goto retry;
}
if (WARN_ON(ret < 0))
ret = connector_status_unknown;
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
return ret;
}
/**
* drm_helper_probe_detect - probe connector status
* @connector: connector to probe
* @ctx: acquire_ctx, or NULL to let this function handle locking.
* @force: Whether destructive probe operations should be performed.
*
* This function calls the detect callbacks of the connector.
* This function returns &drm_connector_status, or
* if @ctx is set, it might also return -EDEADLK.
*/
int
drm_helper_probe_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
struct drm_device *dev = connector->dev;
int ret;
if (!ctx)
return drm_helper_probe_detect_ctx(connector, force);
ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
if (ret)
return ret;
if (funcs->detect_ctx)
return funcs->detect_ctx(connector, ctx, force);
else if (connector->funcs->detect)
return connector->funcs->detect(connector, force);
else
return connector_status_connected;
} }
EXPORT_SYMBOL(drm_helper_probe_detect);
/** /**
* drm_helper_probe_single_connector_modes - get complete set of display modes * drm_helper_probe_single_connector_modes - get complete set of display modes
...@@ -239,15 +300,27 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -239,15 +300,27 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
struct drm_display_mode *mode; struct drm_display_mode *mode;
const struct drm_connector_helper_funcs *connector_funcs = const struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private; connector->helper_private;
int count = 0; int count = 0, ret;
int mode_flags = 0; int mode_flags = 0;
bool verbose_prune = true; bool verbose_prune = true;
enum drm_connector_status old_status; enum drm_connector_status old_status;
struct drm_modeset_acquire_ctx ctx;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
drm_modeset_acquire_init(&ctx, 0);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
connector->name); connector->name);
retry:
ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx);
if (ret == -EDEADLK) {
drm_modeset_backoff(&ctx);
goto retry;
} else
WARN_ON(ret < 0);
/* set all old modes to the stale state */ /* set all old modes to the stale state */
list_for_each_entry(mode, &connector->modes, head) list_for_each_entry(mode, &connector->modes, head)
mode->status = MODE_STALE; mode->status = MODE_STALE;
...@@ -263,7 +336,15 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -263,7 +336,15 @@ 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 = drm_connector_detect(connector, true); ret = drm_helper_probe_detect(connector, &ctx, true);
if (ret == -EDEADLK) {
drm_modeset_backoff(&ctx);
goto retry;
} else if (WARN(ret < 0, "Invalid return value %i for connector detection\n", ret))
ret = connector_status_unknown;
connector->status = ret;
} }
/* /*
...@@ -355,6 +436,9 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -355,6 +436,9 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
prune: prune:
drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); drm_mode_prune_invalid(dev, &connector->modes, verbose_prune);
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
if (list_empty(&connector->modes)) if (list_empty(&connector->modes))
return 0; return 0;
...@@ -440,7 +524,7 @@ static void output_poll_execute(struct work_struct *work) ...@@ -440,7 +524,7 @@ static void output_poll_execute(struct work_struct *work)
repoll = true; repoll = true;
connector->status = drm_connector_detect(connector, false); connector->status = drm_helper_probe_detect(connector, NULL, false);
if (old_status != connector->status) { if (old_status != connector->status) {
const char *old, *new; const char *old, *new;
...@@ -588,7 +672,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) ...@@ -588,7 +672,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
old_status = connector->status; old_status = connector->status;
connector->status = drm_connector_detect(connector, false); connector->status = drm_helper_probe_detect(connector, NULL, false);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
connector->base.id, connector->base.id,
connector->name, connector->name,
......
...@@ -669,15 +669,16 @@ static const struct dmi_system_id intel_spurious_crt_detect[] = { ...@@ -669,15 +669,16 @@ static const struct dmi_system_id intel_spurious_crt_detect[] = {
{ } { }
}; };
static enum drm_connector_status static int
intel_crt_detect(struct drm_connector *connector, bool force) intel_crt_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{ {
struct drm_i915_private *dev_priv = to_i915(connector->dev); struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_crt *crt = intel_attached_crt(connector); struct intel_crt *crt = intel_attached_crt(connector);
struct intel_encoder *intel_encoder = &crt->base; struct intel_encoder *intel_encoder = &crt->base;
enum drm_connector_status status; int status, ret;
struct intel_load_detect_pipe tmp; struct intel_load_detect_pipe tmp;
struct drm_modeset_acquire_ctx ctx;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
connector->base.id, connector->name, connector->base.id, connector->name,
...@@ -721,10 +722,9 @@ intel_crt_detect(struct drm_connector *connector, bool force) ...@@ -721,10 +722,9 @@ intel_crt_detect(struct drm_connector *connector, bool force)
goto out; goto out;
} }
drm_modeset_acquire_init(&ctx, 0);
/* for pre-945g platforms use load detect */ /* for pre-945g platforms use load detect */
if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { ret = intel_get_load_detect_pipe(connector, NULL, &tmp, ctx);
if (ret > 0) {
if (intel_crt_detect_ddc(connector)) if (intel_crt_detect_ddc(connector))
status = connector_status_connected; status = connector_status_connected;
else if (INTEL_GEN(dev_priv) < 4) else if (INTEL_GEN(dev_priv) < 4)
...@@ -734,12 +734,11 @@ intel_crt_detect(struct drm_connector *connector, bool force) ...@@ -734,12 +734,11 @@ intel_crt_detect(struct drm_connector *connector, bool force)
status = connector_status_disconnected; status = connector_status_disconnected;
else else
status = connector_status_unknown; status = connector_status_unknown;
intel_release_load_detect_pipe(connector, &tmp, &ctx); intel_release_load_detect_pipe(connector, &tmp, ctx);
} else } else if (ret == 0)
status = connector_status_unknown; status = connector_status_unknown;
else if (ret < 0)
drm_modeset_drop_locks(&ctx); status = ret;
drm_modeset_acquire_fini(&ctx);
out: out:
intel_display_power_put(dev_priv, intel_encoder->power_domain); intel_display_power_put(dev_priv, intel_encoder->power_domain);
...@@ -811,7 +810,6 @@ void intel_crt_reset(struct drm_encoder *encoder) ...@@ -811,7 +810,6 @@ void intel_crt_reset(struct drm_encoder *encoder)
static const struct drm_connector_funcs intel_crt_connector_funcs = { static const struct drm_connector_funcs intel_crt_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms, .dpms = drm_atomic_helper_connector_dpms,
.detect = intel_crt_detect,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.late_register = intel_connector_register, .late_register = intel_connector_register,
.early_unregister = intel_connector_unregister, .early_unregister = intel_connector_unregister,
...@@ -823,6 +821,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { ...@@ -823,6 +821,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
}; };
static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
.detect_ctx = intel_crt_detect,
.mode_valid = intel_crt_mode_valid, .mode_valid = intel_crt_mode_valid,
.get_modes = intel_crt_get_modes, .get_modes = intel_crt_get_modes,
}; };
......
...@@ -9480,10 +9480,10 @@ static int intel_modeset_setup_plane_state(struct drm_atomic_state *state, ...@@ -9480,10 +9480,10 @@ static int intel_modeset_setup_plane_state(struct drm_atomic_state *state,
return 0; return 0;
} }
bool intel_get_load_detect_pipe(struct drm_connector *connector, int intel_get_load_detect_pipe(struct drm_connector *connector,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct intel_load_detect_pipe *old, struct intel_load_detect_pipe *old,
struct drm_modeset_acquire_ctx *ctx) struct drm_modeset_acquire_ctx *ctx)
{ {
struct intel_crtc *intel_crtc; struct intel_crtc *intel_crtc;
struct intel_encoder *intel_encoder = struct intel_encoder *intel_encoder =
...@@ -9506,10 +9506,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, ...@@ -9506,10 +9506,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
old->restore_state = NULL; old->restore_state = NULL;
retry: WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret)
goto fail;
/* /*
* Algorithm gets a little messy: * Algorithm gets a little messy:
...@@ -9659,10 +9656,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, ...@@ -9659,10 +9656,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
restore_state = NULL; restore_state = NULL;
} }
if (ret == -EDEADLK) { if (ret == -EDEADLK)
drm_modeset_backoff(ctx); return ret;
goto retry;
}
return false; return false;
} }
...@@ -15030,6 +15025,7 @@ static void intel_enable_pipe_a(struct drm_device *dev) ...@@ -15030,6 +15025,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
struct drm_connector *crt = NULL; struct drm_connector *crt = NULL;
struct intel_load_detect_pipe load_detect_temp; struct intel_load_detect_pipe load_detect_temp;
struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx; struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx;
int ret;
/* We can't just switch on the pipe A, we need to set things up with a /* We can't just switch on the pipe A, we need to set things up with a
* proper mode and output configuration. As a gross hack, enable pipe A * proper mode and output configuration. As a gross hack, enable pipe A
...@@ -15046,7 +15042,10 @@ static void intel_enable_pipe_a(struct drm_device *dev) ...@@ -15046,7 +15042,10 @@ static void intel_enable_pipe_a(struct drm_device *dev)
if (!crt) if (!crt)
return; return;
if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx)) ret = intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx);
WARN(ret < 0, "All modeset mutexes are locked, but intel_get_load_detect_pipe failed\n");
if (ret > 0)
intel_release_load_detect_pipe(crt, &load_detect_temp, ctx); intel_release_load_detect_pipe(crt, &load_detect_temp, ctx);
} }
......
...@@ -4566,7 +4566,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp) ...@@ -4566,7 +4566,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
intel_dp->has_audio = false; intel_dp->has_audio = false;
} }
static enum drm_connector_status static int
intel_dp_long_pulse(struct intel_connector *intel_connector) intel_dp_long_pulse(struct intel_connector *intel_connector)
{ {
struct drm_connector *connector = &intel_connector->base; struct drm_connector *connector = &intel_connector->base;
...@@ -4577,6 +4577,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) ...@@ -4577,6 +4577,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
enum drm_connector_status status; enum drm_connector_status status;
u8 sink_irq_vector = 0; u8 sink_irq_vector = 0;
WARN_ON(!drm_modeset_is_locked(&connector->dev->mode_config.connection_mutex));
intel_display_power_get(to_i915(dev), intel_dp->aux_power_domain); intel_display_power_get(to_i915(dev), intel_dp->aux_power_domain);
/* Can't disconnect eDP, but you can close the lid... */ /* Can't disconnect eDP, but you can close the lid... */
...@@ -4635,14 +4637,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) ...@@ -4635,14 +4637,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
status = connector_status_disconnected; status = connector_status_disconnected;
goto out; goto out;
} else if (connector->status == connector_status_connected) { } else if (connector->status == connector_status_connected) {
/*
* If display was connected already and is still connected
* check links status, there has been known issues of
* link loss triggerring long pulse!!!!
*/
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
intel_dp_check_link_status(intel_dp); intel_dp_check_link_status(intel_dp);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
goto out; goto out;
} }
...@@ -4682,11 +4677,13 @@ intel_dp_long_pulse(struct intel_connector *intel_connector) ...@@ -4682,11 +4677,13 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
return status; return status;
} }
static enum drm_connector_status static int
intel_dp_detect(struct drm_connector *connector, bool force) intel_dp_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{ {
struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_dp *intel_dp = intel_attached_dp(connector);
enum drm_connector_status status = connector->status; int status = connector->status;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name); connector->base.id, connector->name);
...@@ -5014,7 +5011,6 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder) ...@@ -5014,7 +5011,6 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
static const struct drm_connector_funcs intel_dp_connector_funcs = { static const struct drm_connector_funcs intel_dp_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms, .dpms = drm_atomic_helper_connector_dpms,
.detect = intel_dp_detect,
.force = intel_dp_force, .force = intel_dp_force,
.fill_modes = drm_helper_probe_single_connector_modes, .fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property, .set_property = intel_dp_set_property,
...@@ -5027,6 +5023,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = { ...@@ -5027,6 +5023,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
}; };
static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = { static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
.detect_ctx = intel_dp_detect,
.get_modes = intel_dp_get_modes, .get_modes = intel_dp_get_modes,
.mode_valid = intel_dp_mode_valid, .mode_valid = intel_dp_mode_valid,
}; };
......
...@@ -1353,10 +1353,10 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); ...@@ -1353,10 +1353,10 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
void vlv_wait_port_ready(struct drm_i915_private *dev_priv, void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
struct intel_digital_port *dport, struct intel_digital_port *dport,
unsigned int expected_mask); unsigned int expected_mask);
bool intel_get_load_detect_pipe(struct drm_connector *connector, int intel_get_load_detect_pipe(struct drm_connector *connector,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct intel_load_detect_pipe *old, struct intel_load_detect_pipe *old,
struct drm_modeset_acquire_ctx *ctx); struct drm_modeset_acquire_ctx *ctx);
void intel_release_load_detect_pipe(struct drm_connector *connector, void intel_release_load_detect_pipe(struct drm_connector *connector,
struct intel_load_detect_pipe *old, struct intel_load_detect_pipe *old,
struct drm_modeset_acquire_ctx *ctx); struct drm_modeset_acquire_ctx *ctx);
......
...@@ -243,7 +243,8 @@ static bool intel_hpd_irq_event(struct drm_device *dev, ...@@ -243,7 +243,8 @@ static bool intel_hpd_irq_event(struct drm_device *dev,
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
old_status = connector->status; old_status = connector->status;
connector->status = connector->funcs->detect(connector, false); connector->status = drm_helper_probe_detect(connector, NULL, false);
if (old_status == connector->status) if (old_status == connector->status)
return false; return false;
......
...@@ -1315,8 +1315,10 @@ static void intel_tv_find_better_format(struct drm_connector *connector) ...@@ -1315,8 +1315,10 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
* Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
* 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 int
intel_tv_detect(struct drm_connector *connector, bool force) intel_tv_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{ {
struct drm_display_mode mode; struct drm_display_mode mode;
struct intel_tv *intel_tv = intel_attached_tv(connector); struct intel_tv *intel_tv = intel_attached_tv(connector);
...@@ -1331,21 +1333,20 @@ intel_tv_detect(struct drm_connector *connector, bool force) ...@@ -1331,21 +1333,20 @@ intel_tv_detect(struct drm_connector *connector, bool force)
if (force) { if (force) {
struct intel_load_detect_pipe tmp; struct intel_load_detect_pipe tmp;
struct drm_modeset_acquire_ctx ctx; int ret;
drm_modeset_acquire_init(&ctx, 0); ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
if (ret < 0)
return ret;
if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { if (ret > 0) {
type = intel_tv_detect_type(intel_tv, connector); type = intel_tv_detect_type(intel_tv, connector);
intel_release_load_detect_pipe(connector, &tmp, &ctx); intel_release_load_detect_pipe(connector, &tmp, ctx);
status = type < 0 ? status = type < 0 ?
connector_status_disconnected : connector_status_disconnected :
connector_status_connected; connector_status_connected;
} else } else
status = connector_status_unknown; status = connector_status_unknown;
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
} else } else
return connector->status; return connector->status;
...@@ -1516,7 +1517,6 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop ...@@ -1516,7 +1517,6 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
static const struct drm_connector_funcs intel_tv_connector_funcs = { static const struct drm_connector_funcs intel_tv_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms, .dpms = drm_atomic_helper_connector_dpms,
.detect = intel_tv_detect,
.late_register = intel_connector_register, .late_register = intel_connector_register,
.early_unregister = intel_connector_unregister, .early_unregister = intel_connector_unregister,
.destroy = intel_tv_destroy, .destroy = intel_tv_destroy,
...@@ -1528,6 +1528,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = { ...@@ -1528,6 +1528,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
}; };
static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
.detect_ctx = intel_tv_detect,
.mode_valid = intel_tv_mode_valid, .mode_valid = intel_tv_mode_valid,
.get_modes = intel_tv_get_modes, .get_modes = intel_tv_get_modes,
}; };
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
struct drm_device; struct drm_device;
struct drm_connector_helper_funcs; struct drm_connector_helper_funcs;
struct drm_modeset_acquire_ctx;
struct drm_device; struct drm_device;
struct drm_crtc; struct drm_crtc;
struct drm_encoder; struct drm_encoder;
...@@ -378,6 +379,11 @@ struct drm_connector_funcs { ...@@ -378,6 +379,11 @@ struct drm_connector_funcs {
* the helper library vtable purely for historical reasons. The only DRM * the helper library vtable purely for historical reasons. The only DRM
* core entry point to probe connector state is @fill_modes. * core entry point to probe connector state is @fill_modes.
* *
* Note that the helper library will already hold
* &drm_mode_config.connection_mutex. Drivers which need to grab additional
* locks to avoid races with concurrent modeset changes need to use
* &drm_connector_helper_funcs.detect_ctx instead.
*
* RETURNS: * RETURNS:
* *
* drm_connector_status indicating the connector's status. * drm_connector_status indicating the connector's status.
......
...@@ -67,6 +67,9 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, ...@@ -67,6 +67,9 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
int drm_helper_probe_single_connector_modes(struct drm_connector int drm_helper_probe_single_connector_modes(struct drm_connector
*connector, uint32_t maxX, *connector, uint32_t maxX,
uint32_t maxY); uint32_t maxY);
int drm_helper_probe_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force);
void drm_kms_helper_poll_init(struct drm_device *dev); void drm_kms_helper_poll_init(struct drm_device *dev);
void drm_kms_helper_poll_fini(struct drm_device *dev); void drm_kms_helper_poll_fini(struct drm_device *dev);
bool drm_helper_hpd_irq_event(struct drm_device *dev); bool drm_helper_hpd_irq_event(struct drm_device *dev);
......
...@@ -747,12 +747,44 @@ struct drm_connector_helper_funcs { ...@@ -747,12 +747,44 @@ struct drm_connector_helper_funcs {
* This callback is used by the probe helpers in e.g. * This callback is used by the probe helpers in e.g.
* drm_helper_probe_single_connector_modes(). * drm_helper_probe_single_connector_modes().
* *
* To avoid races with concurrent connector state updates, the helper
* libraries always call this with the &drm_mode_config.connection_mutex
* held. Because of this it's safe to inspect &drm_connector->state.
*
* RETURNS: * RETURNS:
* *
* The number of modes added by calling drm_mode_probed_add(). * The number of modes added by calling drm_mode_probed_add().
*/ */
int (*get_modes)(struct drm_connector *connector); int (*get_modes)(struct drm_connector *connector);
/**
* @detect_ctx:
*
* Check to see if anything is attached to the connector. The parameter
* force is set to false whilst polling, true when checking the
* connector due to a user request. force can be used by the driver to
* avoid expensive, destructive operations during automated probing.
*
* This callback is optional, if not implemented the connector will be
* considered as always being attached.
*
* This is the atomic version of &drm_connector_funcs.detect.
*
* To avoid races against concurrent connector state updates, the
* helper libraries always call this with ctx set to a valid context,
* and &drm_mode_config.connection_mutex will always be locked with
* the ctx parameter set to this ctx. This allows taking additional
* locks as required.
*
* RETURNS:
*
* &drm_connector_status indicating the connector's status,
* or the error code returned by drm_modeset_lock(), -EDEADLK.
*/
int (*detect_ctx)(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force);
/** /**
* @mode_valid: * @mode_valid:
* *
...@@ -771,6 +803,10 @@ struct drm_connector_helper_funcs { ...@@ -771,6 +803,10 @@ struct drm_connector_helper_funcs {
* CRTC helpers will not call this function. Drivers therefore must * CRTC helpers will not call this function. Drivers therefore must
* still fully validate any mode passed in in a modeset request. * still fully validate any mode passed in in a modeset request.
* *
* To avoid races with concurrent connector state updates, the helper
* libraries always call this with the &drm_mode_config.connection_mutex
* held. Because of this it's safe to inspect &drm_connector->state.
*
* RETURNS: * RETURNS:
* *
* Either &drm_mode_status.MODE_OK or one of the failure reasons in &enum * Either &drm_mode_status.MODE_OK or one of the failure reasons in &enum
......
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