mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 10:30:52 +07:00
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: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Boris Brezillon <boris.brezillon@free-electrons.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/1491504920-4017-1-git-send-email-maarten.lankhorst@linux.intel.com
This commit is contained in:
parent
99748ab64f
commit
6c5ed5ae35
@ -169,13 +169,74 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
|
||||
EXPORT_SYMBOL(drm_kms_helper_poll_enable);
|
||||
|
||||
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 ?
|
||||
connector->funcs->detect(connector, force) :
|
||||
connector_status_connected;
|
||||
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
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
|
||||
* @connector: connector to probe
|
||||
@ -239,15 +300,27 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode;
|
||||
const struct drm_connector_helper_funcs *connector_funcs =
|
||||
connector->helper_private;
|
||||
int count = 0;
|
||||
int count = 0, ret;
|
||||
int mode_flags = 0;
|
||||
bool verbose_prune = true;
|
||||
enum drm_connector_status old_status;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
|
||||
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,
|
||||
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 */
|
||||
list_for_each_entry(mode, &connector->modes, head)
|
||||
mode->status = MODE_STALE;
|
||||
@ -263,7 +336,15 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
if (connector->funcs->force)
|
||||
connector->funcs->force(connector);
|
||||
} 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,
|
||||
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))
|
||||
return 0;
|
||||
|
||||
@ -440,7 +524,7 @@ static void output_poll_execute(struct work_struct *work)
|
||||
|
||||
repoll = true;
|
||||
|
||||
connector->status = drm_connector_detect(connector, false);
|
||||
connector->status = drm_helper_probe_detect(connector, NULL, false);
|
||||
if (old_status != connector->status) {
|
||||
const char *old, *new;
|
||||
|
||||
@ -588,7 +672,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
|
||||
|
||||
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",
|
||||
connector->base.id,
|
||||
connector->name,
|
||||
|
@ -669,15 +669,16 @@ static const struct dmi_system_id intel_spurious_crt_detect[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
static int
|
||||
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 intel_crt *crt = intel_attached_crt(connector);
|
||||
struct intel_encoder *intel_encoder = &crt->base;
|
||||
enum drm_connector_status status;
|
||||
int status, ret;
|
||||
struct intel_load_detect_pipe tmp;
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
|
||||
connector->base.id, connector->name,
|
||||
@ -721,10 +722,9 @@ intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
goto out;
|
||||
}
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
/* 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))
|
||||
status = connector_status_connected;
|
||||
else if (INTEL_GEN(dev_priv) < 4)
|
||||
@ -734,12 +734,11 @@ intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
status = connector_status_disconnected;
|
||||
else
|
||||
status = connector_status_unknown;
|
||||
intel_release_load_detect_pipe(connector, &tmp, &ctx);
|
||||
} else
|
||||
intel_release_load_detect_pipe(connector, &tmp, ctx);
|
||||
} else if (ret == 0)
|
||||
status = connector_status_unknown;
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
else if (ret < 0)
|
||||
status = ret;
|
||||
|
||||
out:
|
||||
intel_display_power_put(dev_priv, intel_encoder->power_domain);
|
||||
@ -811,7 +810,6 @@ void intel_crt_reset(struct drm_encoder *encoder)
|
||||
|
||||
static const struct drm_connector_funcs intel_crt_connector_funcs = {
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.detect = intel_crt_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.late_register = intel_connector_register,
|
||||
.early_unregister = intel_connector_unregister,
|
||||
@ -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 = {
|
||||
.detect_ctx = intel_crt_detect,
|
||||
.mode_valid = intel_crt_mode_valid,
|
||||
.get_modes = intel_crt_get_modes,
|
||||
};
|
||||
|
@ -9480,10 +9480,10 @@ static int intel_modeset_setup_plane_state(struct drm_atomic_state *state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
int intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx)
|
||||
{
|
||||
struct intel_crtc *intel_crtc;
|
||||
struct intel_encoder *intel_encoder =
|
||||
@ -9506,10 +9506,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
|
||||
old->restore_state = NULL;
|
||||
|
||||
retry:
|
||||
ret = drm_modeset_lock(&config->connection_mutex, ctx);
|
||||
if (ret)
|
||||
goto fail;
|
||||
WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
|
||||
|
||||
/*
|
||||
* Algorithm gets a little messy:
|
||||
@ -9659,10 +9656,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
restore_state = NULL;
|
||||
}
|
||||
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(ctx);
|
||||
goto retry;
|
||||
}
|
||||
if (ret == -EDEADLK)
|
||||
return ret;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -15030,6 +15025,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
|
||||
struct drm_connector *crt = NULL;
|
||||
struct intel_load_detect_pipe load_detect_temp;
|
||||
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
|
||||
* 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)
|
||||
if (!crt)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -4566,7 +4566,7 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
|
||||
intel_dp->has_audio = false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
static int
|
||||
intel_dp_long_pulse(struct intel_connector *intel_connector)
|
||||
{
|
||||
struct drm_connector *connector = &intel_connector->base;
|
||||
@ -4577,6 +4577,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
|
||||
enum drm_connector_status status;
|
||||
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);
|
||||
|
||||
/* Can't disconnect eDP, but you can close the lid... */
|
||||
@ -4635,14 +4637,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
|
||||
status = connector_status_disconnected;
|
||||
goto out;
|
||||
} 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);
|
||||
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -4682,11 +4677,13 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_dp_detect(struct drm_connector *connector, bool force)
|
||||
static int
|
||||
intel_dp_detect(struct drm_connector *connector,
|
||||
struct drm_modeset_acquire_ctx *ctx,
|
||||
bool force)
|
||||
{
|
||||
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",
|
||||
connector->base.id, connector->name);
|
||||
@ -5014,7 +5011,6 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
|
||||
|
||||
static const struct drm_connector_funcs intel_dp_connector_funcs = {
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.detect = intel_dp_detect,
|
||||
.force = intel_dp_force,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = intel_dp_set_property,
|
||||
@ -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 = {
|
||||
.detect_ctx = intel_dp_detect,
|
||||
.get_modes = intel_dp_get_modes,
|
||||
.mode_valid = intel_dp_mode_valid,
|
||||
};
|
||||
|
@ -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,
|
||||
struct intel_digital_port *dport,
|
||||
unsigned int expected_mask);
|
||||
bool intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
int intel_get_load_detect_pipe(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
void intel_release_load_detect_pipe(struct drm_connector *connector,
|
||||
struct intel_load_detect_pipe *old,
|
||||
struct drm_modeset_acquire_ctx *ctx);
|
||||
|
@ -243,7 +243,8 @@ static bool intel_hpd_irq_event(struct drm_device *dev,
|
||||
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
|
||||
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)
|
||||
return false;
|
||||
|
||||
|
@ -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
|
||||
* we have a pipe programmed in order to probe the TV.
|
||||
*/
|
||||
static enum drm_connector_status
|
||||
intel_tv_detect(struct drm_connector *connector, bool force)
|
||||
static int
|
||||
intel_tv_detect(struct drm_connector *connector,
|
||||
struct drm_modeset_acquire_ctx *ctx,
|
||||
bool force)
|
||||
{
|
||||
struct drm_display_mode mode;
|
||||
struct intel_tv *intel_tv = intel_attached_tv(connector);
|
||||
@ -1331,21 +1333,20 @@ intel_tv_detect(struct drm_connector *connector, bool force)
|
||||
|
||||
if (force) {
|
||||
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);
|
||||
intel_release_load_detect_pipe(connector, &tmp, &ctx);
|
||||
intel_release_load_detect_pipe(connector, &tmp, ctx);
|
||||
status = type < 0 ?
|
||||
connector_status_disconnected :
|
||||
connector_status_connected;
|
||||
} else
|
||||
status = connector_status_unknown;
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
} else
|
||||
return connector->status;
|
||||
|
||||
@ -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 = {
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.detect = intel_tv_detect,
|
||||
.late_register = intel_connector_register,
|
||||
.early_unregister = intel_connector_unregister,
|
||||
.destroy = intel_tv_destroy,
|
||||
@ -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 = {
|
||||
.detect_ctx = intel_tv_detect,
|
||||
.mode_valid = intel_tv_mode_valid,
|
||||
.get_modes = intel_tv_get_modes,
|
||||
};
|
||||
|
@ -32,6 +32,7 @@
|
||||
struct drm_device;
|
||||
|
||||
struct drm_connector_helper_funcs;
|
||||
struct drm_modeset_acquire_ctx;
|
||||
struct drm_device;
|
||||
struct drm_crtc;
|
||||
struct drm_encoder;
|
||||
@ -378,6 +379,11 @@ struct drm_connector_funcs {
|
||||
* the helper library vtable purely for historical reasons. The only DRM
|
||||
* 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:
|
||||
*
|
||||
* 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,
|
||||
int drm_helper_probe_single_connector_modes(struct drm_connector
|
||||
*connector, uint32_t maxX,
|
||||
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_fini(struct drm_device *dev);
|
||||
bool drm_helper_hpd_irq_event(struct drm_device *dev);
|
||||
|
@ -747,12 +747,44 @@ struct drm_connector_helper_funcs {
|
||||
* This callback is used by the probe helpers in e.g.
|
||||
* 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:
|
||||
*
|
||||
* The number of modes added by calling drm_mode_probed_add().
|
||||
*/
|
||||
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:
|
||||
*
|
||||
@ -771,6 +803,10 @@ struct drm_connector_helper_funcs {
|
||||
* CRTC helpers will not call this function. Drivers therefore must
|
||||
* 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:
|
||||
*
|
||||
* Either &drm_mode_status.MODE_OK or one of the failure reasons in &enum
|
||||
|
Loading…
Reference in New Issue
Block a user